<!DOCTYPE html>
<html>
<head><meta name="generator" content="Hexo 3.8.0">
    

    

    



    <meta charset="utf-8">
    
    
    
    
    <title>前端总结知识点 | lafen | lafen&#39;s personal blog</title>
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
    
    <meta name="theme-color" content="#3F51B5">
    
    
    <meta name="keywords" content="前端">
    <meta name="description" content="总结此处面试总结不是很全，由简单到深入，待整理中… HTML1. HTML5 和 HTML4 区别？ html5 的文件类型声明  1&amp;lt;!DOCTYPE html&amp;gt;  新增语义化标签  1&amp;lt;header&amp;gt;、&amp;lt;footer&amp;gt;、&amp;lt;aside&amp;gt;、&amp;lt;section&amp;gt;、&amp;lt;article&amp;gt;、&amp;lt;nav&amp;gt;  多媒体支持  audi">
<meta name="keywords" content="前端">
<meta property="og:type" content="article">
<meta property="og:title" content="前端总结知识点">
<meta property="og:url" content="https://lafen.gitee.io/2020/03/30/前端总结知识点/前端总结知识点/index.html">
<meta property="og:site_name" content="lafen">
<meta property="og:description" content="总结此处面试总结不是很全，由简单到深入，待整理中… HTML1. HTML5 和 HTML4 区别？ html5 的文件类型声明  1&amp;lt;!DOCTYPE html&amp;gt;  新增语义化标签  1&amp;lt;header&amp;gt;、&amp;lt;footer&amp;gt;、&amp;lt;aside&amp;gt;、&amp;lt;section&amp;gt;、&amp;lt;article&amp;gt;、&amp;lt;nav&amp;gt;  多媒体支持  audi">
<meta property="og:locale" content="zh-CN">
<meta property="og:image" content="https://i.loli.net/2020/08/10/qdOVbymfHUG45rA.jpg">
<meta property="og:updated_time" content="2020-08-10T08:11:06.636Z">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="前端总结知识点">
<meta name="twitter:description" content="总结此处面试总结不是很全，由简单到深入，待整理中… HTML1. HTML5 和 HTML4 区别？ html5 的文件类型声明  1&amp;lt;!DOCTYPE html&amp;gt;  新增语义化标签  1&amp;lt;header&amp;gt;、&amp;lt;footer&amp;gt;、&amp;lt;aside&amp;gt;、&amp;lt;section&amp;gt;、&amp;lt;article&amp;gt;、&amp;lt;nav&amp;gt;  多媒体支持  audi">
<meta name="twitter:image" content="https://i.loli.net/2020/08/10/qdOVbymfHUG45rA.jpg">
    
        <link rel="alternate" type="application/atom+xml" title="lafen" href="/atom.xml">
    
    <link rel="shortcut icon" href="/img/favicon.ico">
    <link rel="stylesheet" href="//unpkg.com/hexo-theme-material-indigo@latest/css/style.css">
    <script>window.lazyScripts=[]</script>

    <!-- custom head -->
    

</head>

<body>
    <div id="loading" class="active"></div>

    <aside id="menu" class="hide">
  <div class="inner flex-row-vertical">
    <a href="javascript:;" class="header-icon waves-effect waves-circle waves-light" id="menu-off">
        <i class="icon icon-lg icon-close"></i>
    </a>
    <div class="brand-wrap" style="background-image:url(/img/brand.jpg)">
      <div class="brand">
        <a href="/" class="avatar waves-effect waves-circle waves-light">
          <img src="/img/avatar.jpg">
        </a>
        <hgroup class="introduce">
          <h5 class="nickname">lafen</h5>
          <a href="mailto:1031822863@qq.com" title="1031822863@qq.com" class="mail">1031822863@qq.com</a>
        </hgroup>
      </div>
    </div>
    <div class="scroll-wrap flex-col">
      <ul class="nav">
        
            <li class="waves-block waves-effect">
              <a href="/">
                <i class="icon icon-lg icon-home"></i>
                home
              </a>
            </li>
        
            <li class="waves-block waves-effect">
              <a href="/archives">
                <i class="icon icon-lg icon-archives"></i>
                Archives
              </a>
            </li>
        
            <li class="waves-block waves-effect">
              <a href="/tags">
                <i class="icon icon-lg icon-tags"></i>
                Tags
              </a>
            </li>
        
            <li class="waves-block waves-effect">
              <a href="/categories">
                <i class="icon icon-lg icon-th-list"></i>
                Categories
              </a>
            </li>
        
            <li class="waves-block waves-effect">
              <a href="https://github.com/zhongxiaotian" target="_blank">
                <i class="icon icon-lg icon-github"></i>
                Github
              </a>
            </li>
        
            <li class="waves-block waves-effect">
              <a href="http://www.weibo.com/" target="_blank">
                <i class="icon icon-lg icon-weibo"></i>
                Weibo
              </a>
            </li>
        
            <li class="waves-block waves-effect">
              <a href="https://gitee.com/lafen" target="_blank">
                <i class="icon icon-lg icon-link"></i>
                Gitee
              </a>
            </li>
        
      </ul>
    </div>
  </div>
</aside>

    <main id="main">
        <header class="top-header" id="header">
    <div class="flex-row">
        <a href="javascript:;" class="header-icon waves-effect waves-circle waves-light on" id="menu-toggle">
          <i class="icon icon-lg icon-navicon"></i>
        </a>
        <div class="flex-col header-title ellipsis">前端总结知识点</div>
        
        <div class="search-wrap" id="search-wrap">
            <a href="javascript:;" class="header-icon waves-effect waves-circle waves-light" id="back">
                <i class="icon icon-lg icon-chevron-left"></i>
            </a>
            <input type="text" id="key" class="search-input" autocomplete="off" placeholder="输入感兴趣的关键字">
            <a href="javascript:;" class="header-icon waves-effect waves-circle waves-light" id="search">
                <i class="icon icon-lg icon-search"></i>
            </a>
        </div>
        
        
        <a href="javascript:;" class="header-icon waves-effect waves-circle waves-light" id="menuShare">
            <i class="icon icon-lg icon-share-alt"></i>
        </a>
        
    </div>
</header>
<header class="content-header post-header">

    <div class="container fade-scale">
        <h1 class="title">前端总结知识点</h1>
        <h5 class="subtitle">
            
                <time datetime="2020-03-30T05:02:18.000Z" itemprop="datePublished" class="page-time">
  2020-03-30
</time>


	<ul class="article-category-list"><li class="article-category-list-item"><a class="article-category-list-link" href="/categories/前端/">前端</a></li></ul>

            
        </h5>
    </div>

    


</header>


<div class="container body-wrap">
    
    <aside class="post-widget">
        <nav class="post-toc-wrap post-toc-shrink" id="post-toc">
            <h4>TOC</h4>
            <ol class="post-toc"><li class="post-toc-item post-toc-level-1"><a class="post-toc-link" href="#总结"><span class="post-toc-number">1.</span> <span class="post-toc-text">总结</span></a><ol class="post-toc-child"><li class="post-toc-item post-toc-level-3"><a class="post-toc-link" href="#HTML"><span class="post-toc-number">1.0.1.</span> <span class="post-toc-text">HTML</span></a><ol class="post-toc-child"><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#1-HTML5-和-HTML4-区别？"><span class="post-toc-number">1.0.1.1.</span> <span class="post-toc-text">1. HTML5 和 HTML4 区别？</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#window-中的五大对象"><span class="post-toc-number">1.0.1.2.</span> <span class="post-toc-text">window 中的五大对象</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#2-src-和-href-的区别"><span class="post-toc-number">1.0.1.3.</span> <span class="post-toc-text">2. src 和 href 的区别</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#3-script-标签中的-defer-和-async-的区别"><span class="post-toc-number">1.0.1.4.</span> <span class="post-toc-text">3. script 标签中的 defer 和 async 的区别</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#5-display-inline-block-问题"><span class="post-toc-number">1.0.1.5.</span> <span class="post-toc-text">5. display: inline-block 问题</span></a></li></ol></li><li class="post-toc-item post-toc-level-3"><a class="post-toc-link" href="#CSS"><span class="post-toc-number">1.0.2.</span> <span class="post-toc-text">CSS</span></a><ol class="post-toc-child"><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#1-盒模型"><span class="post-toc-number">1.0.2.1.</span> <span class="post-toc-text">1. 盒模型</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#2-BFC"><span class="post-toc-number">1.0.2.2.</span> <span class="post-toc-text">2. BFC</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#3-层叠上下文"><span class="post-toc-number">1.0.2.3.</span> <span class="post-toc-text">3. 层叠上下文</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#4-居中布局"><span class="post-toc-number">1.0.2.4.</span> <span class="post-toc-text">4. 居中布局</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#5-选择器优先级"><span class="post-toc-number">1.0.2.5.</span> <span class="post-toc-text">5. 选择器优先级</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#6-去除浮动影响，防止父级高度塌陷"><span class="post-toc-number">1.0.2.6.</span> <span class="post-toc-text">6. 去除浮动影响，防止父级高度塌陷</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#7-link-与-import-的区别"><span class="post-toc-number">1.0.2.7.</span> <span class="post-toc-text">7. link 与 @import 的区别</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#8-css预处理器（sass-less-postcss）"><span class="post-toc-number">1.0.2.8.</span> <span class="post-toc-text">8. css预处理器（sass/less/postcss）</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#9-css动画"><span class="post-toc-number">1.0.2.9.</span> <span class="post-toc-text">9. css动画</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#css-兼容的-4-种方案"><span class="post-toc-number">1.0.2.10.</span> <span class="post-toc-text">css 兼容的 4 种方案</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#margin-重叠问题"><span class="post-toc-number">1.0.2.11.</span> <span class="post-toc-text">margin 重叠问题</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#rgba-和-opacity-的透明效果有什么不同"><span class="post-toc-number">1.0.2.12.</span> <span class="post-toc-text">rgba 和 opacity 的透明效果有什么不同</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#总结-1"><span class="post-toc-number">1.0.2.13.</span> <span class="post-toc-text">总结</span></a></li></ol></li><li class="post-toc-item post-toc-level-3"><a class="post-toc-link" href="#JavaScript"><span class="post-toc-number">1.0.3.</span> <span class="post-toc-text">JavaScript</span></a><ol class="post-toc-child"><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#1-原型、构造函数、实例"><span class="post-toc-number">1.0.3.1.</span> <span class="post-toc-text">1. 原型、构造函数、实例</span></a><ol class="post-toc-child"><li class="post-toc-item post-toc-level-5"><a class="post-toc-link" href="#实例"><span class="post-toc-number">1.0.3.1.1.</span> <span class="post-toc-text">实例</span></a></li></ol></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#2-原型链"><span class="post-toc-number">1.0.3.2.</span> <span class="post-toc-text">2. 原型链</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#3-执行上下文"><span class="post-toc-number">1.0.3.3.</span> <span class="post-toc-text">3. 执行上下文</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#4-变量对象"><span class="post-toc-number">1.0.3.4.</span> <span class="post-toc-text">4. 变量对象</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#5-作用域"><span class="post-toc-number">1.0.3.5.</span> <span class="post-toc-text">5. 作用域</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#6-作用域链"><span class="post-toc-number">1.0.3.6.</span> <span class="post-toc-text">6. 作用域链</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#7-闭包"><span class="post-toc-number">1.0.3.7.</span> <span class="post-toc-text">7. 闭包</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#this指向"><span class="post-toc-number">1.0.3.8.</span> <span class="post-toc-text">this指向</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#箭头函数的理解"><span class="post-toc-number">1.0.3.9.</span> <span class="post-toc-text">箭头函数的理解</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#8-对象拷贝"><span class="post-toc-number">1.0.3.10.</span> <span class="post-toc-text">8. 对象拷贝</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#9-new运算符模拟实现"><span class="post-toc-number">1.0.3.11.</span> <span class="post-toc-text">9. new运算符模拟实现</span></a><ol class="post-toc-child"><li class="post-toc-item post-toc-level-5"><a class="post-toc-link" href="#new-做了什么？"><span class="post-toc-number">1.0.3.11.1.</span> <span class="post-toc-text">new 做了什么？</span></a></li><li class="post-toc-item post-toc-level-5"><a class="post-toc-link" href="#模拟"><span class="post-toc-number">1.0.3.11.2.</span> <span class="post-toc-text">模拟</span></a></li><li class="post-toc-item post-toc-level-5"><a class="post-toc-link" href="#es6版"><span class="post-toc-number">1.0.3.11.3.</span> <span class="post-toc-text">es6版</span></a></li></ol></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#10-instanceof-原理及模拟实现"><span class="post-toc-number">1.0.3.12.</span> <span class="post-toc-text">10. instanceof 原理及模拟实现</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#11-call-模拟实现"><span class="post-toc-number">1.0.3.13.</span> <span class="post-toc-text">11. call 模拟实现</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#12-apply-模拟实现"><span class="post-toc-number">1.0.3.14.</span> <span class="post-toc-text">12. apply 模拟实现</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#13-bind-模拟实现"><span class="post-toc-number">1.0.3.15.</span> <span class="post-toc-text">13. bind 模拟实现</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#14-函数节流与防抖"><span class="post-toc-number">1.0.3.16.</span> <span class="post-toc-text">14. 函数节流与防抖</span></a><ol class="post-toc-child"><li class="post-toc-item post-toc-level-5"><a class="post-toc-link" href="#节流"><span class="post-toc-number">1.0.3.16.1.</span> <span class="post-toc-text">节流</span></a></li><li class="post-toc-item post-toc-level-5"><a class="post-toc-link" href="#防抖"><span class="post-toc-number">1.0.3.16.2.</span> <span class="post-toc-text">防抖</span></a></li></ol></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#15-创建对象实例的方法"><span class="post-toc-number">1.0.3.17.</span> <span class="post-toc-text">15. 创建对象实例的方法</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#16-继承的方式"><span class="post-toc-number">1.0.3.18.</span> <span class="post-toc-text">16. 继承的方式</span></a><ol class="post-toc-child"><li class="post-toc-item post-toc-level-5"><a class="post-toc-link" href="#1-原型链继承"><span class="post-toc-number">1.0.3.18.1.</span> <span class="post-toc-text">1. 原型链继承</span></a></li><li class="post-toc-item post-toc-level-5"><a class="post-toc-link" href="#2-构造继承"><span class="post-toc-number">1.0.3.18.2.</span> <span class="post-toc-text">2. 构造继承</span></a></li><li class="post-toc-item post-toc-level-5"><a class="post-toc-link" href="#3-组合继承"><span class="post-toc-number">1.0.3.18.3.</span> <span class="post-toc-text">3. 组合继承</span></a></li><li class="post-toc-item post-toc-level-5"><a class="post-toc-link" href="#4-寄生组合继承"><span class="post-toc-number">1.0.3.18.4.</span> <span class="post-toc-text">4. 寄生组合继承</span></a></li><li class="post-toc-item post-toc-level-5"><a class="post-toc-link" href="#4-ES6的extend继承"><span class="post-toc-number">1.0.3.18.5.</span> <span class="post-toc-text">4. ES6的extend继承</span></a></li></ol></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#17-高阶函数"><span class="post-toc-number">1.0.3.19.</span> <span class="post-toc-text">17. 高阶函数</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#18-promise"><span class="post-toc-number">1.0.3.20.</span> <span class="post-toc-text">18. promise</span></a><ol class="post-toc-child"><li class="post-toc-item post-toc-level-5"><a class="post-toc-link" href="#promise-题目"><span class="post-toc-number">1.0.3.20.1.</span> <span class="post-toc-text">promise 题目</span></a></li></ol></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#19-generator"><span class="post-toc-number">1.0.3.21.</span> <span class="post-toc-text">19. generator</span></a><ol class="post-toc-child"><li class="post-toc-item post-toc-level-5"><a class="post-toc-link" href="#实现"><span class="post-toc-number">1.0.3.21.1.</span> <span class="post-toc-text">实现</span></a></li></ol></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#20-async-和-await"><span class="post-toc-number">1.0.3.22.</span> <span class="post-toc-text">20. async 和 await</span></a></li></ol></li><li class="post-toc-item post-toc-level-3"><a class="post-toc-link" href="#浏览器"><span class="post-toc-number">1.0.4.</span> <span class="post-toc-text">浏览器</span></a><ol class="post-toc-child"><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#Event-loop"><span class="post-toc-number">1.0.4.1.</span> <span class="post-toc-text">Event loop</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#‘use-strict’"><span class="post-toc-number">1.0.4.2.</span> <span class="post-toc-text">‘use strict’</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#存储"><span class="post-toc-number">1.0.4.3.</span> <span class="post-toc-text">存储</span></a><ol class="post-toc-child"><li class="post-toc-item post-toc-level-5"><a class="post-toc-link" href="#Cookie-弊端"><span class="post-toc-number">1.0.4.3.1.</span> <span class="post-toc-text">Cookie 弊端</span></a></li></ol></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#渲染机制"><span class="post-toc-number">1.0.4.4.</span> <span class="post-toc-text">渲染机制</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#Load-和-DOMContentLoaded-区别"><span class="post-toc-number">1.0.4.5.</span> <span class="post-toc-text">Load 和 DOMContentLoaded 区别</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#图层"><span class="post-toc-number">1.0.4.6.</span> <span class="post-toc-text">图层</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#重绘（Repaint）和回流（Reflow）"><span class="post-toc-number">1.0.4.7.</span> <span class="post-toc-text">重绘（Repaint）和回流（Reflow）</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#减少重绘和回流"><span class="post-toc-number">1.0.4.8.</span> <span class="post-toc-text">减少重绘和回流</span></a></li></ol></li><li class="post-toc-item post-toc-level-3"><a class="post-toc-link" href="#网路攻击"><span class="post-toc-number">1.0.5.</span> <span class="post-toc-text">网路攻击</span></a><ol class="post-toc-child"><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#XSS-攻击"><span class="post-toc-number">1.0.5.1.</span> <span class="post-toc-text">XSS 攻击</span></a><ol class="post-toc-child"><li class="post-toc-item post-toc-level-5"><a class="post-toc-link" href="#什么是-XSS-攻击？"><span class="post-toc-number">1.0.5.1.1.</span> <span class="post-toc-text">什么是 XSS 攻击？</span></a></li><li class="post-toc-item post-toc-level-5"><a class="post-toc-link" href="#XSS-攻击可能存在的危害"><span class="post-toc-number">1.0.5.1.2.</span> <span class="post-toc-text">XSS 攻击可能存在的危害</span></a></li><li class="post-toc-item post-toc-level-5"><a class="post-toc-link" href="#XSS-攻击实现的三种方式"><span class="post-toc-number">1.0.5.1.3.</span> <span class="post-toc-text">XSS 攻击实现的三种方式</span></a><ol class="post-toc-child"><li class="post-toc-item post-toc-level-6"><a class="post-toc-link" href="#存储型"><span class="post-toc-number">1.0.5.1.3.1.</span> <span class="post-toc-text">存储型</span></a></li><li class="post-toc-item post-toc-level-6"><a class="post-toc-link" href="#反射型"><span class="post-toc-number">1.0.5.1.3.2.</span> <span class="post-toc-text">反射型</span></a></li><li class="post-toc-item post-toc-level-6"><a class="post-toc-link" href="#文档型"><span class="post-toc-number">1.0.5.1.3.3.</span> <span class="post-toc-text">文档型</span></a></li></ol></li><li class="post-toc-item post-toc-level-5"><a class="post-toc-link" href="#防范措施"><span class="post-toc-number">1.0.5.1.4.</span> <span class="post-toc-text">防范措施</span></a><ol class="post-toc-child"><li class="post-toc-item post-toc-level-6"><a class="post-toc-link" href="#1-不要相信用户的输入"><span class="post-toc-number">1.0.5.1.4.1.</span> <span class="post-toc-text">1. 不要相信用户的输入</span></a></li><li class="post-toc-item post-toc-level-6"><a class="post-toc-link" href="#2-利用-CSP"><span class="post-toc-number">1.0.5.1.4.2.</span> <span class="post-toc-text">2. 利用 CSP</span></a></li><li class="post-toc-item post-toc-level-6"><a class="post-toc-link" href="#3-利用-HttpOnly"><span class="post-toc-number">1.0.5.1.4.3.</span> <span class="post-toc-text">3. 利用 HttpOnly</span></a></li></ol></li><li class="post-toc-item post-toc-level-5"><a class="post-toc-link" href="#总结-2"><span class="post-toc-number">1.0.5.1.5.</span> <span class="post-toc-text">总结</span></a></li></ol></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#CSRF-攻击"><span class="post-toc-number">1.0.5.2.</span> <span class="post-toc-text">CSRF 攻击</span></a><ol class="post-toc-child"><li class="post-toc-item post-toc-level-5"><a class="post-toc-link" href="#什么是-CSRF-攻击？"><span class="post-toc-number">1.0.5.2.1.</span> <span class="post-toc-text">什么是 CSRF 攻击？</span></a></li><li class="post-toc-item post-toc-level-5"><a class="post-toc-link" href="#防范措施-1"><span class="post-toc-number">1.0.5.2.2.</span> <span class="post-toc-text">防范措施</span></a></li><li class="post-toc-item post-toc-level-5"><a class="post-toc-link" href="#总结-3"><span class="post-toc-number">1.0.5.2.3.</span> <span class="post-toc-text">总结</span></a></li></ol></li></ol></li><li class="post-toc-item post-toc-level-3"><a class="post-toc-link" href="#性能"><span class="post-toc-number">1.0.6.</span> <span class="post-toc-text">性能</span></a><ol class="post-toc-child"><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#网络相关"><span class="post-toc-number">1.0.6.1.</span> <span class="post-toc-text">网络相关</span></a><ol class="post-toc-child"><li class="post-toc-item post-toc-level-5"><a class="post-toc-link" href="#DNS-预解析"><span class="post-toc-number">1.0.6.1.1.</span> <span class="post-toc-text">DNS 预解析</span></a></li></ol></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#长列表性能优化"><span class="post-toc-number">1.0.6.2.</span> <span class="post-toc-text">长列表性能优化</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#v-for-为什么要加上-key-？"><span class="post-toc-number">1.0.6.3.</span> <span class="post-toc-text">v-for 为什么要加上 key ？</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#函数节流、防抖"><span class="post-toc-number">1.0.6.4.</span> <span class="post-toc-text">函数节流、防抖</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#二分法搜索"><span class="post-toc-number">1.0.6.5.</span> <span class="post-toc-text">二分法搜索</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#二叉树的遍历"><span class="post-toc-number">1.0.6.6.</span> <span class="post-toc-text">二叉树的遍历</span></a></li></ol></li><li class="post-toc-item post-toc-level-3"><a class="post-toc-link" href="#计算机"><span class="post-toc-number">1.0.7.</span> <span class="post-toc-text">计算机</span></a><ol class="post-toc-child"><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#网络"><span class="post-toc-number">1.0.7.1.</span> <span class="post-toc-text">网络</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#从输入-URL-到页面加载完成的过程"><span class="post-toc-number">1.0.7.2.</span> <span class="post-toc-text">从输入 URL 到页面加载完成的过程</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#http-状态码"><span class="post-toc-number">1.0.7.3.</span> <span class="post-toc-text">http 状态码</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#http1-0-和-http1-1-区别"><span class="post-toc-number">1.0.7.4.</span> <span class="post-toc-text">http1.0 和 http1.1 区别</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#http-和-https-的区别"><span class="post-toc-number">1.0.7.5.</span> <span class="post-toc-text">http 和 https 的区别</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#前端缓存"><span class="post-toc-number">1.0.7.6.</span> <span class="post-toc-text">前端缓存</span></a><ol class="post-toc-child"><li class="post-toc-item post-toc-level-5"><a class="post-toc-link" href="#强缓存"><span class="post-toc-number">1.0.7.6.1.</span> <span class="post-toc-text">强缓存</span></a></li><li class="post-toc-item post-toc-level-5"><a class="post-toc-link" href="#协商缓存"><span class="post-toc-number">1.0.7.6.2.</span> <span class="post-toc-text">协商缓存</span></a></li><li class="post-toc-item post-toc-level-5"><a class="post-toc-link" href="#缓存位置"><span class="post-toc-number">1.0.7.6.3.</span> <span class="post-toc-text">缓存位置</span></a></li><li class="post-toc-item post-toc-level-5"><a class="post-toc-link" href="#总结-4"><span class="post-toc-number">1.0.7.6.4.</span> <span class="post-toc-text">总结</span></a></li></ol></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#简述三次握手四次挥手"><span class="post-toc-number">1.0.7.7.</span> <span class="post-toc-text">简述三次握手四次挥手</span></a><ol class="post-toc-child"><li class="post-toc-item post-toc-level-5"><a class="post-toc-link" href="#三次握手"><span class="post-toc-number">1.0.7.7.1.</span> <span class="post-toc-text">三次握手</span></a></li><li class="post-toc-item post-toc-level-5"><a class="post-toc-link" href="#四次挥手"><span class="post-toc-number">1.0.7.7.2.</span> <span class="post-toc-text">四次挥手</span></a></li></ol></li></ol></li><li class="post-toc-item post-toc-level-3"><a class="post-toc-link" href="#数据结构"><span class="post-toc-number">1.0.8.</span> <span class="post-toc-text">数据结构</span></a><ol class="post-toc-child"><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#栈"><span class="post-toc-number">1.0.8.1.</span> <span class="post-toc-text">栈</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#队列"><span class="post-toc-number">1.0.8.2.</span> <span class="post-toc-text">队列</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#链表"><span class="post-toc-number">1.0.8.3.</span> <span class="post-toc-text">链表</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#树"><span class="post-toc-number">1.0.8.4.</span> <span class="post-toc-text">树</span></a></li></ol></li><li class="post-toc-item post-toc-level-3"><a class="post-toc-link" href="#算法"><span class="post-toc-number">1.0.9.</span> <span class="post-toc-text">算法</span></a><ol class="post-toc-child"><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#冒泡排序"><span class="post-toc-number">1.0.9.1.</span> <span class="post-toc-text">冒泡排序</span></a><ol class="post-toc-child"><li class="post-toc-item post-toc-level-5"><a class="post-toc-link" href="#冒泡优化–元素交换标志"><span class="post-toc-number">1.0.9.1.1.</span> <span class="post-toc-text">冒泡优化–元素交换标志</span></a></li><li class="post-toc-item post-toc-level-5"><a class="post-toc-link" href="#冒泡优化–无序边界"><span class="post-toc-number">1.0.9.1.2.</span> <span class="post-toc-text">冒泡优化–无序边界</span></a></li><li class="post-toc-item post-toc-level-5"><a class="post-toc-link" href="#冒泡优化–鸡尾酒排序"><span class="post-toc-number">1.0.9.1.3.</span> <span class="post-toc-text">冒泡优化–鸡尾酒排序</span></a></li></ol></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#斐波那契数列"><span class="post-toc-number">1.0.9.2.</span> <span class="post-toc-text">斐波那契数列</span></a></li></ol></li><li class="post-toc-item post-toc-level-3"><a class="post-toc-link" href="#js题目"><span class="post-toc-number">1.0.10.</span> <span class="post-toc-text">js题目</span></a><ol class="post-toc-child"><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#1-考察原型链"><span class="post-toc-number">1.0.10.1.</span> <span class="post-toc-text">1. 考察原型链</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#2-考察this指向"><span class="post-toc-number">1.0.10.2.</span> <span class="post-toc-text">2. 考察this指向</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#3-JS-数据类型概念"><span class="post-toc-number">1.0.10.3.</span> <span class="post-toc-text">3. JS 数据类型概念</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#4-闭包与作用域链"><span class="post-toc-number">1.0.10.4.</span> <span class="post-toc-text">4. 闭包与作用域链</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#5-非匿名的立即执行函数"><span class="post-toc-number">1.0.10.5.</span> <span class="post-toc-text">5. 非匿名的立即执行函数</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#6-ES6-多维数组降维"><span class="post-toc-number">1.0.10.6.</span> <span class="post-toc-text">6. ES6 多维数组降维</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#7-for-in-和-for-of-的区别"><span class="post-toc-number">1.0.10.7.</span> <span class="post-toc-text">7. for in 和 for of 的区别</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#8-和"><span class="post-toc-number">1.0.10.8.</span> <span class="post-toc-text">8. [] == ![] 和 {} == !{}</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#9-js-函数"><span class="post-toc-number">1.0.10.9.</span> <span class="post-toc-text">9. js 函数</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#10-promise-输出顺序问题"><span class="post-toc-number">1.0.10.10.</span> <span class="post-toc-text">10. promise 输出顺序问题</span></a><ol class="post-toc-child"><li class="post-toc-item post-toc-level-5"><a class="post-toc-link" href="#注意："><span class="post-toc-number">1.0.10.10.1.</span> <span class="post-toc-text">注意：</span></a></li><li class="post-toc-item post-toc-level-5"><a class="post-toc-link" href="#理解一下题目"><span class="post-toc-number">1.0.10.10.2.</span> <span class="post-toc-text">理解一下题目</span></a><ol class="post-toc-child"><li class="post-toc-item post-toc-level-6"><a class="post-toc-link" href="#Promise-注册微任务和执行过程"><span class="post-toc-number">1.0.10.10.2.1.</span> <span class="post-toc-text">Promise 注册微任务和执行过程</span></a></li></ol></li></ol></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#数组去重"><span class="post-toc-number">1.0.10.11.</span> <span class="post-toc-text">数组去重</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#运算符优先级"><span class="post-toc-number">1.0.10.12.</span> <span class="post-toc-text">运算符优先级</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#隐式定义全局变量"><span class="post-toc-number">1.0.10.13.</span> <span class="post-toc-text">隐式定义全局变量</span></a></li></ol></li><li class="post-toc-item post-toc-level-3"><a class="post-toc-link" href="#ES6"><span class="post-toc-number">1.0.11.</span> <span class="post-toc-text">ES6</span></a><ol class="post-toc-child"><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#1-es6-新增的主要特性"><span class="post-toc-number">1.0.11.1.</span> <span class="post-toc-text">1. es6 新增的主要特性</span></a></li></ol></li><li class="post-toc-item post-toc-level-3"><a class="post-toc-link" href="#Vue-js-常见题目"><span class="post-toc-number">1.0.12.</span> <span class="post-toc-text">Vue.js 常见题目</span></a><ol class="post-toc-child"><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#1-页面中定义一个定时器，在哪个阶段清除？"><span class="post-toc-number">1.0.12.1.</span> <span class="post-toc-text">1. 页面中定义一个定时器，在哪个阶段清除？</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#2-vue-组件间通信"><span class="post-toc-number">1.0.12.2.</span> <span class="post-toc-text">2. vue 组件间通信</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#3-自定义指令如何定义，他的生命周期"><span class="post-toc-number">1.0.12.3.</span> <span class="post-toc-text">3. 自定义指令如何定义，他的生命周期</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#4-vue-生命周期"><span class="post-toc-number">1.0.12.4.</span> <span class="post-toc-text">4. vue 生命周期</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#5-watch-和-computed-的区别"><span class="post-toc-number">1.0.12.5.</span> <span class="post-toc-text">5. watch 和 computed 的区别</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#6-导航钩子有哪几种？"><span class="post-toc-number">1.0.12.6.</span> <span class="post-toc-text">6. 导航钩子有哪几种？</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#7-vue-中如何通过路由传递数据？区别在哪？"><span class="post-toc-number">1.0.12.7.</span> <span class="post-toc-text">7. vue 中如何通过路由传递数据？区别在哪？</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#8-vue-router-的实现原理，history-和-hash-模式有什么区别"><span class="post-toc-number">1.0.12.8.</span> <span class="post-toc-text">8. vue-router 的实现原理，history 和 hash 模式有什么区别</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#9-vue-中设置-key-的作用"><span class="post-toc-number">1.0.12.9.</span> <span class="post-toc-text">9.  vue 中设置 key 的作用</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#10-vue-中的-diff-算法"><span class="post-toc-number">1.0.12.10.</span> <span class="post-toc-text">10. vue 中的 diff 算法</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#11-vue-中对数据的变化侦测"><span class="post-toc-number">1.0.12.11.</span> <span class="post-toc-text">11. vue 中对数据的变化侦测</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#vue-中对普通对象和-数组-的监听有何不同？"><span class="post-toc-number">1.0.12.12.</span> <span class="post-toc-text">vue 中对普通对象和 数组 的监听有何不同？</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#vue2-数据侦测的缺陷"><span class="post-toc-number">1.0.12.13.</span> <span class="post-toc-text">vue2 数据侦测的缺陷</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#vue-中的设计模式"><span class="post-toc-number">1.0.12.14.</span> <span class="post-toc-text">vue 中的设计模式</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#12-vue-如何优化首屏加载速度"><span class="post-toc-number">1.0.12.15.</span> <span class="post-toc-text">12. vue 如何优化首屏加载速度</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#13-切换到新路由时，页面要滚动到顶部或保持原先滚动位置怎么做？"><span class="post-toc-number">1.0.12.16.</span> <span class="post-toc-text">13. 切换到新路由时，页面要滚动到顶部或保持原先滚动位置怎么做？</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#14-nextTick-使用场景"><span class="post-toc-number">1.0.12.17.</span> <span class="post-toc-text">14. $nextTick() 使用场景</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#15-vue-和-react-的区别"><span class="post-toc-number">1.0.12.18.</span> <span class="post-toc-text">15. vue 和 react 的区别</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#vuex-简述"><span class="post-toc-number">1.0.12.19.</span> <span class="post-toc-text">vuex 简述</span></a></li></ol></li><li class="post-toc-item post-toc-level-3"><a class="post-toc-link" href="#Axios-相关"><span class="post-toc-number">1.0.13.</span> <span class="post-toc-text">Axios 相关</span></a></li><li class="post-toc-item post-toc-level-3"><a class="post-toc-link" href="#性能优化"><span class="post-toc-number">1.0.14.</span> <span class="post-toc-text">性能优化</span></a><ol class="post-toc-child"><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#1-预加载和懒加载"><span class="post-toc-number">1.0.14.1.</span> <span class="post-toc-text">1. 预加载和懒加载</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#2-spa-单页应用和多页应用的选型场景"><span class="post-toc-number">1.0.14.2.</span> <span class="post-toc-text">2. spa 单页应用和多页应用的选型场景</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#3-js-实现重定向的几种方式"><span class="post-toc-number">1.0.14.3.</span> <span class="post-toc-text">3. js 实现重定向的几种方式</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#css-兼容的-4-种方案-1"><span class="post-toc-number">1.0.14.4.</span> <span class="post-toc-text">css 兼容的 4 种方案</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#margin-越界问题"><span class="post-toc-number">1.0.14.5.</span> <span class="post-toc-text">margin 越界问题</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#js-深拷贝"><span class="post-toc-number">1.0.14.6.</span> <span class="post-toc-text">js 深拷贝</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#如何性能优化？从几个点进行？"><span class="post-toc-number">1.0.14.7.</span> <span class="post-toc-text">如何性能优化？从几个点进行？</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#缓存有哪些？"><span class="post-toc-number">1.0.14.8.</span> <span class="post-toc-text">缓存有哪些？</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#SPA-项目优化"><span class="post-toc-number">1.0.14.9.</span> <span class="post-toc-text">SPA 项目优化</span></a></li></ol></li><li class="post-toc-item post-toc-level-3"><a class="post-toc-link" href="#webpack"><span class="post-toc-number">1.0.15.</span> <span class="post-toc-text">webpack</span></a><ol class="post-toc-child"><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#webpack-是怎么进行打包的？"><span class="post-toc-number">1.0.15.1.</span> <span class="post-toc-text">webpack 是怎么进行打包的？</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#webpack-构建流程？"><span class="post-toc-number">1.0.15.2.</span> <span class="post-toc-text">webpack 构建流程？</span></a></li></ol></li><li class="post-toc-item post-toc-level-3"><a class="post-toc-link" href="#参考："><span class="post-toc-number">1.0.16.</span> <span class="post-toc-text">参考：</span></a></li></ol></li></ol>
        </nav>
    </aside>


<article id="post-前端总结知识点/前端总结知识点" class="post-article article-type-post fade" itemprop="blogPost">

    <div class="post-card">
        <h1 class="post-card-title">前端总结知识点</h1>
        <div class="post-meta">
            <time class="post-time" title="2020-03-30 13:02:18" datetime="2020-03-30T05:02:18.000Z" itemprop="datePublished">2020-03-30</time>

            
	<ul class="article-category-list"><li class="article-category-list-item"><a class="article-category-list-link" href="/categories/前端/">前端</a></li></ul>



            
<span id="busuanzi_container_page_pv" title="文章总阅读量" style="display:none">
    <i class="icon icon-eye icon-pr"></i><span id="busuanzi_value_page_pv"></span>
</span>


        </div>
        <div class="post-content" id="post-content" itemprop="postContent">
            <h1 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h1><p>此处面试总结不是很全，由简单到深入，待整理中…</p>
<h3 id="HTML"><a href="#HTML" class="headerlink" title="HTML"></a>HTML</h3><h4 id="1-HTML5-和-HTML4-区别？"><a href="#1-HTML5-和-HTML4-区别？" class="headerlink" title="1. HTML5 和 HTML4 区别？"></a>1. HTML5 和 HTML4 区别？</h4><ol>
<li>html5 的文件类型声明</li>
</ol>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;!DOCTYPE html&gt;</span></span><br></pre></td></tr></table></figure>
<ol start="2">
<li>新增语义化标签</li>
</ol>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">header</span>&gt;</span>、<span class="tag">&lt;<span class="name">footer</span>&gt;</span>、<span class="tag">&lt;<span class="name">aside</span>&gt;</span>、<span class="tag">&lt;<span class="name">section</span>&gt;</span>、<span class="tag">&lt;<span class="name">article</span>&gt;</span>、<span class="tag">&lt;<span class="name">nav</span>&gt;</span></span><br></pre></td></tr></table></figure>
<ol start="3">
<li>多媒体支持</li>
</ol>
<p>audio、video 标签</p>
<ol start="4">
<li>input 的 type 属性</li>
</ol>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">email、url、number、date、time、datetime、datetime-local、month、week、</span><br></pre></td></tr></table></figure>
<ol start="5">
<li>储存</li>
</ol>
<p>cookie： 保存在浏览器端，大小为 4K</p>
<p>localStorage： 生命周期是永久的，必须手动清除，大小可达到 5M</p>
<p>sessionStorage： 生命周期为当前标签页，关闭则清除，大小可达到 5M</p>
<h4 id="window-中的五大对象"><a href="#window-中的五大对象" class="headerlink" title="window 中的五大对象"></a>window 中的五大对象</h4><p>Navigator、Screen、History、Location、Window</p>
<h4 id="2-src-和-href-的区别"><a href="#2-src-和-href-的区别" class="headerlink" title="2. src 和 href 的区别"></a>2. src 和 href 的区别</h4><ul>
<li><code>href</code> 用于在当前文档和引用资源之间确立关系</li>
<li><code>src</code> 用于替换当前内容</li>
</ul>
<p>浏览器解析方式</p>
<ul>
<li>当浏览器遇到 <code>href</code> 会并行下载资源并且不会停止对当前文档的处理（所以建议使用 <code>link</code> 方式加载 <code>css</code> 而不是 <code>@import</code> 方式）</li>
<li>当浏览器解析到 <code>src</code> ，会暂停其他资源的下载和处理，直到将该资源加载完毕或执行完毕。（所以建议 <code>script</code> 标签放在底部）</li>
</ul>
<h4 id="3-script-标签中的-defer-和-async-的区别"><a href="#3-script-标签中的-defer-和-async-的区别" class="headerlink" title="3. script 标签中的 defer 和 async 的区别"></a>3. script 标签中的 defer 和 async 的区别</h4><p>默认情况下，脚本的下载和执行会按照文档的先后顺序同步进行。当脚本下载和执行的时候，文档解析就会被阻塞，在脚本下载和执行完成之后文档才能往下继续解析。</p>
<ul>
<li>当 <code>script</code> 中有 <code>defer</code> 属性时，脚本的加载过程和文档加载是异步发生的，等到文档解析完（<code>DOMContentLoader</code> 事件发生）脚本才开始执行</li>
<li>当 <code>script</code> 中有 <code>async</code> 属性时，脚本的加载过程和文档加载是异步发生的，但脚本下载完成后会停止 <code>HTML</code> 解析，执行脚本，脚本执行完继续 <code>HTML</code> 解析</li>
<li>当 <code>script</code> 同时有 <code>async</code> 和 <code>defer</code> 属性时，执行效果和 <code>async</code> 一致</li>
</ul>
<h4 id="5-display-inline-block-问题"><a href="#5-display-inline-block-问题" class="headerlink" title="5. display: inline-block 问题"></a>5. display: inline-block 问题</h4><p><strong>问题：</strong></p>
<p>两个 <code>display: inline-block</code> 元素并排会产生一段空白</p>
<p><strong>原因：</strong></p>
<p>元素被当成行内元素排版的时候，元素之间的空白符（空格、回车等）都会被浏览器处理，根据 <code>css</code> 中 <code>white-space</code> 属性的处理方式（<code>normal</code> 合并多余空白），原来 <code>HTML</code> 代码中的回车换行被转成了一个空白符，在字体不为 <code>0</code> 的情况下，空白符占据一定的宽度，所以导致出现了空隙</p>
<p><strong>解决：</strong></p>
<ul>
<li>将子元素的结束标签与下一个子元素的开始标签书写在同一行（蛋疼）</li>
<li>设置父元素 <code>font-size: 0</code>，子元素设置正确的 <code>font-size</code></li>
<li>子元素浮动 <code>float: left</code></li>
</ul>
<h3 id="CSS"><a href="#CSS" class="headerlink" title="CSS"></a>CSS</h3><h4 id="1-盒模型"><a href="#1-盒模型" class="headerlink" title="1. 盒模型"></a>1. 盒模型</h4><p>布局模型可通过 <code>box-sizing</code> 进行设置，不同值，其计算区域不同：</p>
<table>
<thead>
<tr>
<th>模型</th>
<th>box-sizing</th>
<th>计算区域</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>W3C 标准盒模型</strong>（默认）</td>
<td>content-box</td>
<td>width/height</td>
</tr>
<tr>
<td><strong>IE盒模型</strong></td>
<td>border-box</td>
<td>width/height+padding+border</td>
</tr>
<tr>
<td>其他</td>
<td>padding-box</td>
<td>width/height+padding</td>
</tr>
</tbody>
</table>
<h4 id="2-BFC"><a href="#2-BFC" class="headerlink" title="2. BFC"></a>2. BFC</h4><p><strong>块级格式上下文</strong>，是一个独立渲染的区域，让处于 <code>BFC</code> 内部的元素与外部的元素相互隔离，使内外元素的定位不会相互影响</p>
<blockquote>
<p>IE下为Layout，可通过 zoom: 1 触发</p>
</blockquote>
<ul>
<li><p>触发条件：</p>
<ul>
<li>根元素</li>
<li>position: absolute / fixed</li>
<li>display: inline-block / table</li>
<li>float 不为 none</li>
<li>overflow 不为 visible</li>
</ul>
</li>
<li><p>规则：</p>
<ul>
<li>属于同一个 <code>BFC</code> 的两个相邻 <code>Box</code> 垂直排列</li>
<li>属于同一个 <code>BFC</code> 的两个相邻 <code>Box</code> 的 <code>margin</code> 会发生重叠</li>
<li><code>BFC</code> 区域不会与 <code>float</code> 的元素区域重叠</li>
<li>计算 <code>BFC</code> 的高度时，浮动子元素也参与计算</li>
<li>文字层不会被浮动层覆盖，环绕于四周</li>
</ul>
</li>
<li><p>应用：</p>
<ul>
<li>阻止 <code>margin</code> 重叠</li>
<li>清除内部浮动（两个浮动元素都处于同一个 <code>BFC</code> 区域中）</li>
<li>自适应两栏布局</li>
<li>可以阻止元素被浮动元素覆盖</li>
</ul>
</li>
</ul>
<h4 id="3-层叠上下文"><a href="#3-层叠上下文" class="headerlink" title="3. 层叠上下文"></a>3. 层叠上下文</h4><ul>
<li><p>触发条件</p>
<ul>
<li>根层叠上下文（<code>html</code>）</li>
<li><code>position</code></li>
<li><code>CSS3</code> 属性<ul>
<li>flex</li>
<li>transform</li>
<li>opacity</li>
<li>filter</li>
<li>will-change</li>
<li>-webkit-overflow-scrolling</li>
</ul>
</li>
</ul>
</li>
<li><p>层叠等级</p>
<p>层叠上下文在 <code>z</code> 轴上的排序</p>
<ul>
<li>在同一层叠上下文中，层叠等级的比较才有意义</li>
<li><code>z-index</code> 的优先级最高</li>
</ul>
</li>
</ul>
<figure class="image-bubble">
                <div class="img-lightbox">
                    <div class="overlay"></div>
                    <img src="https://i.loli.net/2020/08/10/qdOVbymfHUG45rA.jpg" alt="层叠上下文.jpg" title="">
                </div>
                <div class="image-caption">层叠上下文.jpg</div>
            </figure>
<h4 id="4-居中布局"><a href="#4-居中布局" class="headerlink" title="4. 居中布局"></a>4. 居中布局</h4><ul>
<li>水平居中<ul>
<li>行内元素： <code>text-align: center</code></li>
<li>块级元素： <code>maigin: 0 auto</code></li>
<li><code>absolute + transform</code></li>
<li><code>flex + justify-content: center</code></li>
</ul>
</li>
<li><p>垂直居中</p>
<ul>
<li><code>line-height: height</code>（并非真的居中，除非 <code>font-size: 0</code>）</li>
<li><code>absolute + tranform</code></li>
<li><code>flex + align-items: center</code></li>
<li><code>table</code></li>
</ul>
</li>
<li><p>水平垂直居中</p>
<ul>
<li><code>absolute + tranform</code></li>
<li><code>flex + justify-content + align-items</code></li>
</ul>
</li>
</ul>
<h4 id="5-选择器优先级"><a href="#5-选择器优先级" class="headerlink" title="5. 选择器优先级"></a>5. 选择器优先级</h4><ul>
<li>!import &gt; 行内样式 &gt; #id &gt; .class &gt; tag &gt; * &gt; 继承 &gt; 默认</li>
<li>选择器 <strong>从右往左</strong> 解析，所以选择器最好不要嵌套太深</li>
</ul>
<h4 id="6-去除浮动影响，防止父级高度塌陷"><a href="#6-去除浮动影响，防止父级高度塌陷" class="headerlink" title="6. 去除浮动影响，防止父级高度塌陷"></a>6. 去除浮动影响，防止父级高度塌陷</h4><ul>
<li>伪元素清除浮动<ul>
<li>::after { clear: both … }</li>
</ul>
</li>
<li>创建 <code>BFC</code></li>
<li>父级设置高度，或 <code>overflow: hidden</code></li>
</ul>
<h4 id="7-link-与-import-的区别"><a href="#7-link-与-import-的区别" class="headerlink" title="7. link 与 @import 的区别"></a>7. link 与 @import 的区别</h4><ul>
<li><code>link</code>功能较多，可定义 <code>RSS</code>，定义 <code>Rel</code> 等作用，而 <code>@import</code> 只能用于加载 <code>css</code></li>
<li>当解析到 <code>link</code> 时，页面会同步加载所引的 <code>css</code>，而 <code>@import</code> 所引用的 <code>css</code> 会等到页面加载完才会被加载</li>
<li><code>@import</code> 需要 <code>ie5</code> 以上才能使用</li>
<li><code>link</code> 可以通过 <code>js</code> 动态引入，<code>@import</code> 不行</li>
</ul>
<h4 id="8-css预处理器（sass-less-postcss）"><a href="#8-css预处理器（sass-less-postcss）" class="headerlink" title="8. css预处理器（sass/less/postcss）"></a>8. css预处理器（sass/less/postcss）</h4><p>原理：将类 <code>css</code> 语言通过 <code>Webpack</code> 编译转成浏览器可读的真正的 <code>css</code>，在编译过程中，可使用非常强大的功能，如</p>
<ul>
<li>嵌套</li>
<li>变量</li>
<li>循环语句</li>
<li>条件语句</li>
<li>自动添加浏览器前缀</li>
<li>单位转换</li>
<li><code>mixin</code> 复用</li>
</ul>
<h4 id="9-css动画"><a href="#9-css动画" class="headerlink" title="9. css动画"></a>9. css动画</h4><ul>
<li><code>transition</code> 过渡动画</li>
<li><code>animation / keyframes</code></li>
</ul>
<h4 id="css-兼容的-4-种方案"><a href="#css-兼容的-4-种方案" class="headerlink" title="css 兼容的 4 种方案"></a>css 兼容的 4 种方案</h4><ul>
<li>浏览器 <code>css</code> 样式初始化 （ normalize.css ）</li>
<li>浏览器私有属性（ css 属性前缀，如 -webkit-、-moz-、-ms-）</li>
<li>css hack 写法</li>
<li><strong>自动化插件（ Autoprefixer 插件 ）</strong></li>
</ul>
<h4 id="margin-重叠问题"><a href="#margin-重叠问题" class="headerlink" title="margin 重叠问题"></a>margin 重叠问题</h4><ul>
<li><p>概念：即 <strong>外边距合并</strong>，当普通文档流中两个 <strong>垂直外边距</strong> 相遇时，将发生合并为外边距较大者（发生在上下兄弟元素之前，或父子元素之间），但左右外边距不会合并</p>
</li>
<li><p>合并规则：</p>
<ul>
<li>两外边距都为正数，合并结果为两者中较大的值</li>
<li>两外边距都为负数，合并结果为两者绝对值中较大的值</li>
<li>两外边距一正一负，合并结果为两者相加的和</li>
</ul>
</li>
</ul>
<h4 id="rgba-和-opacity-的透明效果有什么不同"><a href="#rgba-和-opacity-的透明效果有什么不同" class="headerlink" title="rgba 和 opacity 的透明效果有什么不同"></a>rgba 和 opacity 的透明效果有什么不同</h4><ul>
<li><code>opacity</code> 作用于元素，以及元素内所有的内容的透明度</li>
<li><code>rgba</code> 只作用于元素的颜色或其背景色，其子元素和内容不会继承透明效果</li>
</ul>
<h4 id="总结-1"><a href="#总结-1" class="headerlink" title="总结"></a>总结</h4><p><code>css</code> 部分，还是推荐慕课网上，张鑫旭老师的视频课程，对于<code>position、line-height、float</code> 等都讲解非常详细，还有《css世界》</p>
<h3 id="JavaScript"><a href="#JavaScript" class="headerlink" title="JavaScript"></a>JavaScript</h3><p>做填空，后面做记录，先记个大纲</p>
<h4 id="1-原型、构造函数、实例"><a href="#1-原型、构造函数、实例" class="headerlink" title="1. 原型、构造函数、实例"></a>1. 原型、构造函数、实例</h4><ul>
<li><p>原型（<code>prototype</code>）：一个对象，每一个 <code>js</code> 对象都有 <code>__proto__</code>（<code>es6</code> 之前是非标准属性）属性指向该对象的原型，可通过 <code>obj.__proto__</code> 进行访问</p>
</li>
<li><p>构造函数： 可通过 <code>new</code> 来创建一个对象的函数</p>
</li>
<li>实例： 通过 <code>new</code> 构造函数创建出来的对象，实例通过 <code>__proto__</code> 指向原型，原型通过 <code>constructor</code> 指向构造函数</li>
</ul>
<h5 id="实例"><a href="#实例" class="headerlink" title="实例"></a>实例</h5><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">Person</span>(<span class="params">name, age</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">this</span>.name = name</span><br><span class="line">    <span class="keyword">this</span>.age = age</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">var</span> p = <span class="keyword">new</span> Person(<span class="string">'lafen'</span>, <span class="number">18</span>)</span><br><span class="line"></span><br><span class="line">p.__proto__ === Person.prototype <span class="comment">// true，实例对象的 __proto__ 指向构造函数的原型对象</span></span><br><span class="line">Person.prototype.constructor === Person <span class="comment">// true，原型对象的 constructor 指向构造函数</span></span><br><span class="line">Person.prototype.__proto__ === <span class="built_in">Object</span>.prototype <span class="comment">// true，原型对象其实也是实例对象，由Object 构造函数生成</span></span><br></pre></td></tr></table></figure>
<h4 id="2-原型链"><a href="#2-原型链" class="headerlink" title="2. 原型链"></a>2. 原型链</h4><p><strong>原型链</strong>由原型对象组成，每个对象都有 <code>__proto__</code> 属性，指向了创建该对象的<strong>构造函数的原型</strong>，<code>__proto__</code> 将对象连接起来组成<strong>原型链</strong>。是一个用来实现继承和共享属性的有限的对象链。</p>
<h4 id="3-执行上下文"><a href="#3-执行上下文" class="headerlink" title="3. 执行上下文"></a>3. 执行上下文</h4><p><a href="https://github.com/mqyqingfeng/Blog" target="_blank" rel="noopener">冴羽博客</a></p>
<h4 id="4-变量对象"><a href="#4-变量对象" class="headerlink" title="4. 变量对象"></a>4. 变量对象</h4><p>变量对象是执行上下文中的一部分，可以抽象为一种数据作用域，也可以简单理解为一个简单的对象，他存着该执行上下文的所有变量和函数声明（不包含函数表达式）</p>
<blockquote>
<p>活动对象（AO）：当变量对象所处的上下文为active EC时，称为活动对象</p>
</blockquote>
<h4 id="5-作用域"><a href="#5-作用域" class="headerlink" title="5. 作用域"></a>5. 作用域</h4><p>执行上下文中还包含作用域链，作用域链可以理解为该上下文中声明的变量和声明的作用范围，可分为<strong>全局作用域</strong>和<strong>函数作用域</strong>（<code>ES5</code> 中），<code>ES6</code> 中新增块级作用域</p>
<p>ES5：</p>
<ul>
<li>全局作用域</li>
<li>函数作用域</li>
</ul>
<p>ES6新增：</p>
<ul>
<li>块级作用域（其中的<strong>作用域链不复存在</strong>）</li>
</ul>
<h4 id="6-作用域链"><a href="#6-作用域链" class="headerlink" title="6. 作用域链"></a>6. 作用域链</h4><p><code>ES5</code> 中只存在两种作用域：全局作用域 和 函数作用域。（<code>ES6</code> 中新增块级作用域，其中的作用域链不复存在）</p>
<p>当访问一个变量时，解析器会首先在当前作用域中查找，如果没有找到就会去父作用域中查找，直到全局作用域（<code>window</code>），这就是作用域链。</p>
<blockquote>
<p>每个子函数都会拷贝上级的作用域，形成一个作用域的链条</p>
</blockquote>
<h4 id="7-闭包"><a href="#7-闭包" class="headerlink" title="7. 闭包"></a>7. 闭包</h4><p>红宝书上定义为：闭包是指有权访问另一个函数作用域中的变量的函数。（本质上只需要让父级作用域的引用存在即可）</p>
<h4 id="this指向"><a href="#this指向" class="headerlink" title="this指向"></a>this指向</h4><p>函数执行时才能确定 <code>this</code> 到底指向谁，谁调用就指向谁（大部分情况下可以这么理解）</p>
<ul>
<li>全局作用域下 <code>this</code> 指向 <code>window</code></li>
<li>箭头函数中 <code>this</code> 指向与外层环境相关</li>
<li><code>ie</code> 事件对象中 <code>this</code> 指向 <code>window</code>，不指向当前元素</li>
<li><code>setTimeout</code> 中 <code>this</code> 指向 <code>window</code></li>
<li>构造函数中的 <code>this</code> 指向实例出来的对象</li>
</ul>
<h4 id="箭头函数的理解"><a href="#箭头函数的理解" class="headerlink" title="箭头函数的理解"></a>箭头函数的理解</h4><ul>
<li><strong>没有 this</strong>，this 指向为最近一层非箭头函数的 this</li>
<li><strong>没有 arguments</strong>，arguments 访问的是外层函数的 arguments 对象</li>
<li><strong>不能通过 new</strong> 关键字创建</li>
<li><strong>没有原型</strong>，即没有 prototype 属性</li>
<li><strong>没有 super</strong> ，super 由外层非箭头函数决定</li>
</ul>
<h4 id="8-对象拷贝"><a href="#8-对象拷贝" class="headerlink" title="8. 对象拷贝"></a>8. 对象拷贝</h4><ul>
<li>浅拷贝<ul>
<li><code>Object.assign</code></li>
<li>展开运算符（<code>...</code>）</li>
</ul>
</li>
<li>深拷贝<ul>
<li><code>JSON.parse(JSON.stringify(obj))</code> 简单快速<ul>
<li>具有循环引用的对象时，报错</li>
<li>无法处理函数、<code>undefined</code>、<code>symbol</code></li>
</ul>
</li>
<li>递归进行逐一赋值</li>
</ul>
</li>
</ul>
<h4 id="9-new运算符模拟实现"><a href="#9-new运算符模拟实现" class="headerlink" title="9. new运算符模拟实现"></a>9. new运算符模拟实现</h4><h5 id="new-做了什么？"><a href="#new-做了什么？" class="headerlink" title="new 做了什么？"></a>new 做了什么？</h5><ul>
<li>创建一个新对象</li>
<li>将新对象的 <code>__proto__</code> 指向构造函数的 <code>prototype</code></li>
<li>将 <code>this</code> 指向该新对象，执行构造函数</li>
<li>返回这个新对象</li>
</ul>
<h5 id="模拟"><a href="#模拟" class="headerlink" title="模拟"></a>模拟</h5><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">objectFactory</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">    <span class="keyword">var</span> obj = <span class="keyword">new</span> <span class="built_in">Object</span>() <span class="comment">// 新建一个对象</span></span><br><span class="line">    <span class="keyword">var</span> Ctor = [].shift.call(<span class="built_in">arguments</span>) <span class="comment">// 拿到构造函数，shift会改变原数据</span></span><br><span class="line">    obj.__proto__ = Ctor.prototype <span class="comment">// 指向构造器的原型对象</span></span><br><span class="line">    <span class="keyword">var</span> res = Ctor.apply(obj, <span class="built_in">arguments</span>) <span class="comment">// 执行构造函数，传入参数</span></span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">typeof</span> res === <span class="string">'object'</span> ? res : obj <span class="comment">// 返回</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h5 id="es6版"><a href="#es6版" class="headerlink" title="es6版"></a>es6版</h5><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// es6版</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">objectFactory</span>(<span class="params">Ctor, ...rest</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">let</span> obj = <span class="built_in">Object</span>.create(Ctor.prototype)</span><br><span class="line">    <span class="keyword">let</span> res = Ctor.apply(obj, rest)</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">typeof</span> res === <span class="string">'object'</span> ? res : obj</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h4 id="10-instanceof-原理及模拟实现"><a href="#10-instanceof-原理及模拟实现" class="headerlink" title="10. instanceof 原理及模拟实现"></a>10. instanceof 原理及模拟实现</h4><p>能够在<strong>实例的原型对象链中</strong>找到该<strong>构造函数</strong>的 <code>prototype</code> 属性所指向的<strong>原型对象</strong>，就返回 <code>true</code></p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">instanceof</span>(<span class="params">left, right</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">var</span> proto = left.__proto__ <span class="comment">// 对象的原型</span></span><br><span class="line">    <span class="keyword">var</span> prototype = right.prototype <span class="comment">// 类型的原型</span></span><br><span class="line">    <span class="keyword">while</span>(<span class="literal">true</span>) &#123;</span><br><span class="line">        <span class="keyword">if</span>(proto === <span class="literal">null</span>) <span class="keyword">return</span> <span class="literal">false</span></span><br><span class="line">        <span class="keyword">if</span>(proto === prototype) <span class="keyword">return</span> <span class="literal">true</span></span><br><span class="line">        proto = proto.__proto__ <span class="comment">// 向上查找</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">var</span> obj = &#123;&#125;</span><br><span class="line"><span class="keyword">instanceof</span>(obj, <span class="built_in">Object</span>) <span class="comment">// 模拟obj instanceof Object</span></span><br></pre></td></tr></table></figure>
<h4 id="11-call-模拟实现"><a href="#11-call-模拟实现" class="headerlink" title="11. call 模拟实现"></a>11. call 模拟实现</h4><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">Function</span>.prototype.mycall = <span class="function"><span class="keyword">function</span>(<span class="params">context</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">var</span> context = context || <span class="built_in">window</span> <span class="comment">// 获取要指向的对象</span></span><br><span class="line">    context.fn = <span class="keyword">this</span> <span class="comment">// 获取 mycall 的调用者方法</span></span><br><span class="line">    <span class="keyword">var</span> args = [...arguments].slice(<span class="number">1</span>) <span class="comment">// 获取参数</span></span><br><span class="line">    <span class="keyword">var</span> result = context.fn(...args) <span class="comment">// 调用方法，传入参数</span></span><br><span class="line">    <span class="keyword">delete</span> context.fn <span class="comment">// 删除方法</span></span><br><span class="line">    <span class="keyword">return</span> result <span class="comment">// 返回结果</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h4 id="12-apply-模拟实现"><a href="#12-apply-模拟实现" class="headerlink" title="12. apply 模拟实现"></a>12. apply 模拟实现</h4><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">Function</span>.prototype.myapply = <span class="function"><span class="keyword">function</span>(<span class="params">context</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">var</span> context = context || <span class="built_in">window</span></span><br><span class="line">    context.fn = <span class="keyword">this</span> <span class="comment">// 调用者方法</span></span><br><span class="line">    <span class="keyword">var</span> result = <span class="literal">null</span></span><br><span class="line">    <span class="keyword">if</span>(<span class="built_in">arguments</span>[<span class="number">1</span>]) &#123;</span><br><span class="line">       <span class="comment">// 如果存在第二个参数，则传入</span></span><br><span class="line">       result = context.fn(...arguments)</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        result = context.fn()</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">delete</span> context.fn</span><br><span class="line">    <span class="keyword">return</span> result</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h4 id="13-bind-模拟实现"><a href="#13-bind-模拟实现" class="headerlink" title="13. bind 模拟实现"></a>13. bind 模拟实现</h4><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">Function</span>.prototype.mybind = <span class="function"><span class="keyword">function</span>(<span class="params">context</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">var</span> fn = <span class="keyword">this</span> <span class="comment">// 调用者</span></span><br><span class="line">    <span class="keyword">var</span> args = [...arguments].slice(<span class="number">1</span>) <span class="comment">// 获取参数</span></span><br><span class="line">    <span class="keyword">return</span> <span class="function"><span class="keyword">function</span> <span class="title">Fn</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> fn.apply(<span class="keyword">this</span> <span class="keyword">instanceof</span> Fn</span><br><span class="line">                        ? <span class="keyword">this</span></span><br><span class="line">                        : context,</span><br><span class="line">                        args.concat(...arguments))</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h4 id="14-函数节流与防抖"><a href="#14-函数节流与防抖" class="headerlink" title="14. 函数节流与防抖"></a>14. 函数节流与防抖</h4><table>
<thead>
<tr>
<th>类型</th>
<th>概念</th>
<th>应用</th>
</tr>
</thead>
<tbody>
<tr>
<td>节流</td>
<td>事件触发后每隔一段时间触发一次，可触发多次</td>
<td>scroll、resize 事件一段时间触发多次</td>
</tr>
<tr>
<td>防抖</td>
<td>事件触发动作完成一段时间触发一次</td>
<td>scroll、resize 事件触发完后一段时间触发</td>
</tr>
</tbody>
</table>
<h5 id="节流"><a href="#节流" class="headerlink" title="节流"></a>节流</h5><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> throttle = <span class="function"><span class="keyword">function</span>(<span class="params">func, delay</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">let</span> timer = <span class="literal">null</span></span><br><span class="line">    <span class="keyword">return</span> <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">        <span class="comment">// 延迟回调还存在时不可重新注册</span></span><br><span class="line">        <span class="keyword">if</span>(!timer) &#123;</span><br><span class="line">            timer = setTimeout(<span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">                func.apply(<span class="keyword">this</span>, <span class="built_in">arguments</span>)</span><br><span class="line">                timer = <span class="literal">null</span> <span class="comment">// 执行完毕之后置为null，让其可以重新注册延迟回调</span></span><br><span class="line">            &#125;, delay)</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// 处理函数</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">handle</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="built_in">Math</span>.random())</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// 监听事件</span></span><br><span class="line"><span class="built_in">window</span>.addEventListener(<span class="string">'scroll'</span>, throttle(handle, <span class="number">1000</span>))</span><br></pre></td></tr></table></figure>
<h5 id="防抖"><a href="#防抖" class="headerlink" title="防抖"></a>防抖</h5><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">debounce</span>(<span class="params">fn, wait</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">var</span> timer = <span class="literal">null</span></span><br><span class="line">    <span class="keyword">return</span> <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">        <span class="comment">// 如果多次触发，则将上次记录延迟清除掉</span></span><br><span class="line">        <span class="keyword">if</span>(timer) clearTimeout(timer)</span><br><span class="line">        timer = setTimeout(<span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">            fn.apply(<span class="keyword">this</span>, <span class="built_in">arguments</span>)</span><br><span class="line">            timer = <span class="literal">null</span></span><br><span class="line">        &#125;, wait)</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// 处理函数</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">handle</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="built_in">Math</span>.random())</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// 滚动事件</span></span><br><span class="line"><span class="built_in">window</span>.addEventListener(<span class="string">'scroll'</span>, debounce(handle, <span class="number">1000</span>))</span><br></pre></td></tr></table></figure>
<h4 id="15-创建对象实例的方法"><a href="#15-创建对象实例的方法" class="headerlink" title="15. 创建对象实例的方法"></a>15. 创建对象实例的方法</h4><ol>
<li>字面量</li>
</ol>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> obj = &#123; <span class="attr">name</span>: <span class="string">'lafen'</span> &#125;</span><br></pre></td></tr></table></figure>
<ol start="2">
<li>Object 构造函数创建</li>
</ol>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> obj = <span class="keyword">new</span> <span class="built_in">Object</span>()</span><br><span class="line">obj.name = <span class="string">'lafen'</span></span><br></pre></td></tr></table></figure>
<ol start="3">
<li>使用工厂模式创建对象</li>
</ol>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">createObject</span>(<span class="params">name</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">var</span> obj = <span class="keyword">new</span> <span class="built_in">Object</span>()</span><br><span class="line">    obj.name = name</span><br><span class="line">    <span class="keyword">return</span> obj</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">var</span> p = createObject(<span class="string">'lafen'</span>)</span><br></pre></td></tr></table></figure>
<ol start="4">
<li>使用构造函数创建对象</li>
</ol>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">Person</span>(<span class="params">name</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">this</span>.name = name</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">var</span> p = <span class="keyword">new</span> Person(name)</span><br></pre></td></tr></table></figure>
<h4 id="16-继承的方式"><a href="#16-继承的方式" class="headerlink" title="16. 继承的方式"></a>16. <a href="http://47.98.159.95/my_blog/js-base/006.html#%E7%AC%AC%E4%B8%80%E7%A7%8D-%E5%80%9F%E5%8A%A9call" target="_blank" rel="noopener">继承的方式</a></h4><h5 id="1-原型链继承"><a href="#1-原型链继承" class="headerlink" title="1. 原型链继承"></a>1. 原型链继承</h5><p>将父类的实例作为子类的原型</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 定义父类</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">Animal</span>(<span class="params">name</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">this</span>.name = name || <span class="string">'Animal'</span> <span class="comment">// 属性</span></span><br><span class="line">    <span class="keyword">this</span>.sleep = <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">        <span class="built_in">console</span>.log(<span class="keyword">this</span>.name + <span class="string">' 正在睡觉！'</span>)</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// 原型方法</span></span><br><span class="line">Animal.prototype.eat = <span class="function"><span class="keyword">function</span>(<span class="params">food</span>) </span>&#123;</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="keyword">this</span>.name + <span class="string">' 吃 '</span> + food)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 子类</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">Cat</span>(<span class="params"></span>) </span>&#123;&#125;</span><br><span class="line">Cat.prototype = <span class="keyword">new</span> Animal() <span class="comment">// 将子类原型指向父类实例</span></span><br><span class="line">Cat.prototype.name = <span class="string">'cat'</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> cat = <span class="keyword">new</span> Cat()</span><br><span class="line"><span class="built_in">console</span>.log(cat.name) <span class="comment">// cat</span></span><br><span class="line">cat.eat(<span class="string">'fish'</span>) <span class="comment">// cat 吃 fish</span></span><br><span class="line">cat.sleep() <span class="comment">// cat 正在睡觉！</span></span><br><span class="line"><span class="built_in">console</span>.log(cat <span class="keyword">instanceof</span> Animal) <span class="comment">// true</span></span><br><span class="line"><span class="built_in">console</span>.log(cat <span class="keyword">instanceof</span> Cat) <span class="comment">// true</span></span><br></pre></td></tr></table></figure>
<p>优点： </p>
<ul>
<li>简单易于实现</li>
<li>父类新增原型方法和属性，子类都能访问到</li>
<li>实例是子类的实例，也是父类的实例</li>
</ul>
<p>缺点：</p>
<ul>
<li><p>新增子类属性和方法，必须在 new Animal() 之后</p>
</li>
<li><p>无法实现多继承</p>
</li>
<li>来自原型对象的所有属性被所有实例共享</li>
<li>创建子类时，无法向父类构造函数传参</li>
</ul>
<h5 id="2-构造继承"><a href="#2-构造继承" class="headerlink" title="2. 构造继承"></a>2. 构造继承</h5><p>实际上是用 <code>call</code> 来改变 <code>Cat</code> 中的 <code>this</code> 指向</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">Cat</span>(<span class="params">name</span>) </span>&#123;</span><br><span class="line">    Animal.call(<span class="keyword">this</span>)</span><br><span class="line">    <span class="keyword">this</span>.name = name || <span class="string">'cat'</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>优缺点：</p>
<ul>
<li>可以实现多继承</li>
<li>可以向父类传递参数</li>
<li>不能继承原型属性/方法</li>
</ul>
<h5 id="3-组合继承"><a href="#3-组合继承" class="headerlink" title="3. 组合继承"></a>3. 组合继承</h5><p>通过调用父类构造函数，继承父类的属性并保留传参的优点，然后通过将父类实例作为子类原型，实现函数复用</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">Cat</span>(<span class="params">name</span>) </span>&#123;</span><br><span class="line">    Animal.call(<span class="keyword">this</span>)</span><br><span class="line">    <span class="keyword">this</span>.name = name || <span class="string">'cat'</span></span><br><span class="line">&#125;</span><br><span class="line">Cat.prototype = <span class="keyword">new</span> Animal()</span><br><span class="line">Cat.prototype.constructor = Cat <span class="comment">// 修复构造函数指向</span></span><br></pre></td></tr></table></figure>
<h5 id="4-寄生组合继承"><a href="#4-寄生组合继承" class="headerlink" title="4. 寄生组合继承"></a>4. 寄生组合继承</h5><p>通过寄生方式，砍掉父类的实例属性，这样在调用两次父类的构造函数的时候，就不会初始化两次实例方法和属性，避免组合继承的缺点</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">Cat</span>(<span class="params">name</span>) </span>&#123;</span><br><span class="line">    Animal.call(<span class="keyword">this</span>);</span><br><span class="line">    <span class="keyword">this</span>.name = name || <span class="string">'cat'</span></span><br><span class="line">&#125;</span><br><span class="line">(<span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">    <span class="comment">// 创建一个没有实例方法的类</span></span><br><span class="line">    <span class="keyword">var</span> Super = <span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;&#125;;</span><br><span class="line">    Super.prototype = Animal.prototype;</span><br><span class="line">    <span class="comment">// 将实例作为子类的原型</span></span><br><span class="line">    Cat.prototype = <span class="keyword">new</span> Super()</span><br><span class="line">&#125;)();</span><br><span class="line">Cat.prototype.constructor = Cat; <span class="comment">// 需要修复下构造函数</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> cat = <span class="keyword">new</span> Cat();</span><br><span class="line"><span class="built_in">console</span>.log(cat.name);</span><br><span class="line"><span class="built_in">console</span>.log(cat.sleep());</span><br><span class="line"><span class="built_in">console</span>.log(cat <span class="keyword">instanceof</span> Animal); <span class="comment">// true</span></span><br><span class="line"><span class="built_in">console</span>.log(cat <span class="keyword">instanceof</span> Cat); <span class="comment">//true</span></span><br></pre></td></tr></table></figure>
<h5 id="4-ES6的extend继承"><a href="#4-ES6的extend继承" class="headerlink" title="4. ES6的extend继承"></a>4. ES6的extend继承</h5><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Person</span> </span>&#123;</span><br><span class="line">    <span class="comment">//构造方法</span></span><br><span class="line">    <span class="keyword">constructor</span>(skin, language) &#123;</span><br><span class="line">        <span class="keyword">this</span>.skin = skin</span><br><span class="line">        <span class="keyword">this</span>.language = language</span><br><span class="line">    &#125;</span><br><span class="line">    say() &#123;</span><br><span class="line">        <span class="built_in">console</span>.log(<span class="string">'父类说话的方法'</span>)</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Chinese</span> <span class="keyword">extends</span> <span class="title">Person</span> </span>&#123;</span><br><span class="line">    <span class="keyword">constructor</span>(skin, language, positon) &#123;</span><br><span class="line">        <span class="keyword">super</span>(skin, language) <span class="comment">// 先调用 super</span></span><br><span class="line">        <span class="comment">//super();相当于父类的构造函数</span></span><br><span class="line">        <span class="comment">//console.log(this);调用super后得到了this，不报错，this指向子类，相当于调用了父类.prototype.constructor.call(this)</span></span><br><span class="line">        <span class="keyword">this</span>.positon = positon</span><br><span class="line">    &#125;</span><br><span class="line">    aboutMe() &#123;</span><br><span class="line">        <span class="built_in">console</span>.log(<span class="string">`<span class="subst">$&#123;<span class="keyword">this</span>.skin&#125;</span> <span class="subst">$&#123;<span class="keyword">this</span>.language&#125;</span>  <span class="subst">$&#123;<span class="keyword">this</span>.positon&#125;</span>`</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//调用只能通过new的方法得到实例,再调用里面的方法</span></span><br><span class="line"><span class="keyword">let</span> obj = <span class="keyword">new</span> Chinese(<span class="string">'黄色'</span>, <span class="string">'中文'</span>, <span class="string">'香港'</span>);</span><br><span class="line">obj.aboutMe();</span><br><span class="line">obj.say();</span><br></pre></td></tr></table></figure>
<h4 id="17-高阶函数"><a href="#17-高阶函数" class="headerlink" title="17. 高阶函数"></a>17. 高阶函数</h4><ol>
<li>定义</li>
</ol>
<p>函数的参数是函数或返回函数，即高阶函数</p>
<ol start="2">
<li>常见的高阶函数</li>
</ol>
<p>map、reduce、filter、sort…</p>
<ol start="3">
<li>函数柯里化</li>
</ol>
<p>只传递给函数一部分参数来调用它，让它返回一个函数去处理剩下的参数</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">fn(a, b, c, d) =&gt; fn(a)(b)(c)(d)</span><br></pre></td></tr></table></figure>
<p>柯里化</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 初步封装</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">curry</span>(<span class="params">fn</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">var</span> args = <span class="built_in">Array</span>.prototype.slice.call(<span class="built_in">arguments</span>, <span class="number">1</span>)</span><br><span class="line">    <span class="keyword">return</span> <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">        <span class="keyword">var</span> innserArgs = <span class="built_in">Array</span>.prototype.slice.call(<span class="built_in">arguments</span>)</span><br><span class="line">        <span class="keyword">var</span> finalArgs = args.concat(innerArgs)</span><br><span class="line">        <span class="keyword">return</span> fn.apply(<span class="keyword">this</span>, finalArgs)</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// 将其柯里化</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">add</span>(<span class="params">num1, num2</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> num1 + num2</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// 使用</span></span><br><span class="line"><span class="keyword">var</span> curriedAdd = curry(add, <span class="number">5</span>)</span><br><span class="line">curriedAdd(<span class="number">3</span>)</span><br><span class="line"><span class="comment">// 或者一下传两个参</span></span><br><span class="line"><span class="keyword">var</span> curriedAdd2 = curry(add, <span class="number">5</span>, <span class="number">3</span>)</span><br><span class="line">curriedAdd()</span><br></pre></td></tr></table></figure>
<ol start="4">
<li>函数反柯里化</li>
</ol>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">obj.func(arg1, arg2) =&gt; func(obj, arg1, arg2)</span><br></pre></td></tr></table></figure>
<p>反柯里化</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">Function</span>.prototype.uncurrying = <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">    <span class="keyword">var</span> that = <span class="keyword">this</span></span><br><span class="line">    <span class="keyword">return</span> <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="built_in">Function</span>.prototype.call.apply(that, <span class="built_in">arguments</span>)</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">sayHi</span> (<span class="params"></span>) </span>&#123;</span><br><span class="line">  <span class="keyword">return</span> <span class="string">"Hello "</span> + <span class="keyword">this</span>.value +<span class="string">" "</span>+[].slice.call(<span class="built_in">arguments</span>);</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">let</span> sayHiuncurrying=sayHi.uncurrying();</span><br><span class="line"><span class="built_in">console</span>.log(sayHiuncurrying(&#123;<span class="attr">value</span>:<span class="string">'world'</span>&#125;,<span class="string">"hahaha"</span>));</span><br></pre></td></tr></table></figure>
<ol start="5">
<li>偏函数</li>
</ol>
<p>指定部分参数来返回一个新的定制函数的形式</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">foo</span>(<span class="params">a, b, c</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> a + b + c</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">func</span>(<span class="params">a, b</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> foo(a, b, <span class="number">8</span>)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<ol start="6">
<li>惰性载入函数</li>
</ol>
<p>避免多次进行不必要的能力检测</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 覆盖</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">createXHR</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">    <span class="comment">// 能力检测只进行了一次</span></span><br><span class="line">    <span class="keyword">if</span>(<span class="keyword">typeof</span> XMLHttpRequest != <span class="string">'undefined'</span>) &#123;</span><br><span class="line">        createXHR = <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;&#125; <span class="comment">// 重新覆盖createXHR函数</span></span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        createXHR = <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;&#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// 返回函数</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">createXHR</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">    <span class="keyword">if</span>(<span class="keyword">typeof</span> XMLHttpRequest != <span class="string">'undefined'</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;&#125; <span class="comment">// 返回函数</span></span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;&#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h4 id="18-promise"><a href="#18-promise" class="headerlink" title="18. promise"></a>18. promise</h4><p>promise 解决了回调地狱的问题。</p>
<p>promise 三种状态：</p>
<ul>
<li>pending（异步任务正在执行，只能变更为成功或失败，且不可逆）</li>
<li>resolved（fulfilled）（异步任务执行成功）</li>
<li>rejected（异步任务执行失败）</li>
</ul>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 未实现链式调用</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Promise</span> </span>&#123;</span><br><span class="line">    <span class="keyword">constructor</span>(executor) &#123;</span><br><span class="line">        <span class="keyword">this</span>.state = <span class="string">'pending'</span> <span class="comment">// 状态</span></span><br><span class="line">        </span><br><span class="line">        <span class="keyword">this</span>.value = <span class="literal">undefined</span> <span class="comment">// 成功结果</span></span><br><span class="line">        <span class="keyword">this</span>.reason = <span class="literal">undefined</span> <span class="comment">// 失败原因</span></span><br><span class="line">        </span><br><span class="line">        <span class="keyword">this</span>.onResolvedCallbacks = [] <span class="comment">// 成功回调队列</span></span><br><span class="line">        <span class="keyword">this</span>.onRejectedCallbacks = [] <span class="comment">// 失败回调队列</span></span><br><span class="line">        </span><br><span class="line">        <span class="comment">// resolve 函数</span></span><br><span class="line">        <span class="keyword">let</span> resolve = <span class="function"><span class="params">value</span> =&gt;</span> &#123;</span><br><span class="line">            <span class="keyword">if</span>(<span class="keyword">this</span>.state === <span class="string">'pending'</span>) &#123;</span><br><span class="line">                <span class="keyword">this</span>.state = <span class="string">'fulfilled'</span></span><br><span class="line">                <span class="keyword">this</span>.value = value</span><br><span class="line">                <span class="keyword">this</span>.onResolvedCallbacks.forEach(<span class="function"><span class="params">fn</span> =&gt;</span> fn())</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        </span><br><span class="line">        <span class="comment">// reject 函数</span></span><br><span class="line">        <span class="keyword">let</span> reject = <span class="function"><span class="params">reason</span> =&gt;</span> &#123;</span><br><span class="line">            <span class="keyword">if</span>(<span class="keyword">this</span>.state === <span class="string">'pending'</span>) &#123;</span><br><span class="line">                <span class="keyword">this</span>.state = <span class="string">'rejected'</span></span><br><span class="line">                <span class="keyword">this</span>.reason = reason</span><br><span class="line">                <span class="keyword">this</span>.onRejectedCallbacks.forEach(<span class="function"><span class="params">fn</span> =&gt;</span> fn())</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        </span><br><span class="line">        <span class="comment">// 立即执行 executor</span></span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            executor(resolve, reject)</span><br><span class="line">        &#125; <span class="keyword">catch</span>(err) &#123;</span><br><span class="line">            reject(err)</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// then 方法</span></span><br><span class="line">    then(onFulfilled, onRejected) &#123;</span><br><span class="line">        <span class="keyword">if</span>(<span class="keyword">this</span>.state === <span class="string">'fulfilled'</span>) &#123;</span><br><span class="line">            onFulfilled(<span class="keyword">this</span>.value)</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span>(<span class="keyword">this</span>.state === <span class="string">'rejected'</span>) &#123;</span><br><span class="line">            onRejected(<span class="keyword">this</span>.reason)</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">// 如果状态未改变，则压入队列中</span></span><br><span class="line">        <span class="keyword">if</span>(<span class="keyword">this</span>.state === <span class="string">'pending'</span>) &#123;</span><br><span class="line">            <span class="keyword">this</span>.onFulfilledCallbacks.push(<span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">                onFulfilled(<span class="keyword">this</span>.value)</span><br><span class="line">            &#125;)</span><br><span class="line">            <span class="keyword">this</span>.onRejectedCallbacks.push(<span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">                onRejected(<span class="keyword">this</span>.reason)</span><br><span class="line">            &#125;)</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h5 id="promise-题目"><a href="#promise-题目" class="headerlink" title="promise 题目"></a><a href="https://mp.weixin.qq.com/s/op3EaSXKTCXwYt_uRvhePg" target="_blank" rel="noopener">promise 题目</a></h5><h4 id="19-generator"><a href="#19-generator" class="headerlink" title="19. generator"></a>19. <a href="https://yuchengkai.cn/docs/frontend/#generator-%E5%AE%9E%E7%8E%B0" target="_blank" rel="noopener">generator</a></h4><p>Generator 是 ES6 中的新语法，和 Promise 一样，都可以用来异步编程</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 使用 * 表示这是一个 Generator 函数</span></span><br><span class="line"><span class="comment">// 内部可以通过 yield 暂停代码</span></span><br><span class="line"><span class="comment">// 通过调用 next 恢复执行</span></span><br><span class="line"><span class="function"><span class="keyword">function</span>* <span class="title">test</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">  <span class="keyword">let</span> a = <span class="number">1</span> + <span class="number">2</span>;</span><br><span class="line">  <span class="keyword">yield</span> <span class="number">2</span>;</span><br><span class="line">  <span class="keyword">yield</span> <span class="number">3</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">let</span> b = test();</span><br><span class="line"><span class="built_in">console</span>.log(b) <span class="comment">// </span></span><br><span class="line"><span class="built_in">console</span>.log(b.next()); <span class="comment">// &gt;  &#123; value: 2, done: false &#125;</span></span><br><span class="line"><span class="built_in">console</span>.log(b.next()); <span class="comment">// &gt;  &#123; value: 3, done: false &#125;</span></span><br><span class="line"><span class="built_in">console</span>.log(b.next()); <span class="comment">// &gt;  &#123; value: undefined, done: true &#125;</span></span><br></pre></td></tr></table></figure>
<p>加上 * 的函数执行后会返回一个 Generator 的实例对象，可访问 next 函数，每次调用 next 函数可以继续执行被暂停的代码</p>
<h5 id="实现"><a href="#实现" class="headerlink" title="实现"></a>实现</h5><h4 id="20-async-和-await"><a href="#20-async-和-await" class="headerlink" title="20. async 和 await"></a>20. <a href="https://yuchengkai.cn/docs/frontend/#async-%E5%92%8C-await" target="_blank" rel="noopener">async 和 await</a></h4><p>async 修饰的函数将返回一个 Promise，可以看成函数将返回值使用 Promise.resolve() 包裹了下</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">async</span> <span class="function"><span class="keyword">function</span> <span class="title">test</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">  <span class="keyword">return</span> <span class="string">"1"</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="built_in">console</span>.log(test()); <span class="comment">// -&gt; Promise &#123;&lt;resolved&gt;: "1"&#125;</span></span><br></pre></td></tr></table></figure>
<p>await 只能在 async 函数中使用</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">sleep</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">  <span class="keyword">return</span> <span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="function"><span class="params">resolve</span> =&gt;</span> &#123;</span><br><span class="line">    setTimeout(<span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">      <span class="built_in">console</span>.log(<span class="string">'finish'</span>)</span><br><span class="line">      resolve(<span class="string">"sleep"</span>);</span><br><span class="line">    &#125;, <span class="number">2000</span>);</span><br><span class="line">  &#125;);</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">async</span> <span class="function"><span class="keyword">function</span> <span class="title">test</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">  <span class="keyword">let</span> value = <span class="keyword">await</span> sleep();</span><br><span class="line">  <span class="built_in">console</span>.log(<span class="string">"object"</span>);</span><br><span class="line">&#125;</span><br><span class="line">test()</span><br></pre></td></tr></table></figure>
<p><strong>理解以下代码</strong></p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> a = <span class="number">0</span></span><br><span class="line"><span class="keyword">var</span> b = <span class="keyword">async</span> () =&gt; &#123;</span><br><span class="line">  a = a + <span class="keyword">await</span> <span class="number">10</span></span><br><span class="line">  <span class="built_in">console</span>.log(<span class="string">'2'</span>, a) <span class="comment">// -&gt; '2' 10</span></span><br><span class="line">  a = (<span class="keyword">await</span> <span class="number">10</span>) + a</span><br><span class="line">  <span class="built_in">console</span>.log(<span class="string">'3'</span>, a) <span class="comment">// -&gt; '3' 20</span></span><br><span class="line">&#125;</span><br><span class="line">b()</span><br><span class="line">a++</span><br><span class="line"><span class="built_in">console</span>.log(<span class="string">'1'</span>, a) <span class="comment">// -&gt; '1' 1</span></span><br></pre></td></tr></table></figure>
<ul>
<li>首先函数 <code>b</code> 会先执行，在执行到 <code>await 10</code> 之前，变量 <code>a</code> 还是 <code>0</code> ，因为在 <code>await</code> 内部实现了 <code>generators</code>，<code>generators</code> 会保留堆栈中的东西，所以这个时候 <code>a = 0</code> 被保存了下来</li>
<li>因为 <code>await</code> 是异步操作，遇到 <code>await</code> 就会立即返回一个 <code>pending</code> 状态的 <code>Promise</code> 对象，暂时返回执行代码的控制权，使得函数外的代码得以继续执行，所以会先执行  <code>console.log(&#39;1&#39;, a)</code></li>
<li>这时候同步代码执行完毕，开始执行异步代码，将保存下来的值拿出来使用，这时候 <code>a = 10</code></li>
<li>然后就是常规的执行代码了</li>
</ul>
<h3 id="浏览器"><a href="#浏览器" class="headerlink" title="浏览器"></a>浏览器</h3><h4 id="Event-loop"><a href="#Event-loop" class="headerlink" title="Event loop"></a><a href="https://lafen.gitee.io/2019/09/27/js-%E5%AE%8F%E4%BB%BB%E5%8A%A1%E5%92%8C%E5%BE%AE%E4%BB%BB%E5%8A%A1/js-%E5%AE%8F%E4%BB%BB%E5%8A%A1%E5%92%8C%E5%BE%AE%E4%BB%BB%E5%8A%A1/">Event loop</a></h4><p>浏览器执行机制（简单总结）：</p>
<ul>
<li>主线程首先会顺序执行 <code>script</code> 标签内程序，遇到异步任务，则将异步任务压入<strong>事件队列</strong>中注册，事件队列分为<strong>微任务</strong>和<strong>宏任务</strong></li>
<li>下一步检查异步队列中<strong>微任务</strong>队列，有微任务则将所有微任务执行清空</li>
<li>然后检查<strong>宏任务</strong>队列，将其中回调函数放入主线程执行，不断循环以上过程即浏览器执行机制</li>
</ul>
<h4 id="‘use-strict’"><a href="#‘use-strict’" class="headerlink" title="‘use strict’"></a>‘use strict’</h4><p>指严格运行模式，使 <code>js</code> 在更严格的条件下运行。目的：</p>
<ul>
<li>消除 <code>js</code> 语法的一些不合理、不严谨的地方，减少一些怪异行为</li>
<li>消除代码运行的一些不安全之处，保证代码运行的安全</li>
<li>提高编译器效率，增加运行速度</li>
<li>为未来新版本的 <code>js</code> 做好铺垫</li>
</ul>
<p>区别：</p>
<ul>
<li>禁止使用 <code>with</code> 语句</li>
<li>禁止 <code>this</code> 指向全局对象</li>
<li>对象不能有重名属性</li>
</ul>
<h4 id="存储"><a href="#存储" class="headerlink" title="存储"></a>存储</h4><p>cookie、localStorage、sessionStorage、indexDB</p>
<h5 id="Cookie-弊端"><a href="#Cookie-弊端" class="headerlink" title="Cookie 弊端"></a>Cookie 弊端</h5><ol>
<li><code>cookie</code> 数量和长度限制，每个域名最多只能有 <code>20</code> 条 <code>cookie</code>，每个 <code>cookie</code> 长度不能超过 <code>4kb</code> ，否则会被截断</li>
<li>安全性问题，如果 <code>cookie</code> 被人拦截，那就可以获取所有的 <code>session</code> 信息，只要按需发送 <code>cookie</code> 即达到目的</li>
</ol>
<h4 id="渲染机制"><a href="#渲染机制" class="headerlink" title="渲染机制"></a><a href="https://yuchengkai.cn/docs/frontend/browser.html#%E6%B8%B2%E6%9F%93%E6%9C%BA%E5%88%B6" target="_blank" rel="noopener">渲染机制</a></h4><p>浏览器的渲染一般分为以下几个步骤：</p>
<ol>
<li>处理 <code>HTML</code> 并构建 <code>DOM</code> 树</li>
<li>处理 <code>CSS</code> 构建 <code>CSSOM</code> 树</li>
<li>将 <code>DOM</code> 与 <code>CSSOM</code> 合并成一个渲染树</li>
<li>根据渲染树来布局，计算每个节点的位置</li>
<li>调用 <code>GPU</code> 绘制，合成图层，显示在屏幕上</li>
</ol>
<p>在构建 <code>CSSOM</code> 树时，会阻塞渲染，直至 <code>CSSOM</code> 树构建完成，并且构建 <code>CSSOM</code> 树是一个十分消耗性能的过程，所以应该尽量保持层级扁平，减少过渡层叠，越是具体的 <code>CSS</code> 选择器，执行速度越慢。</p>
<p>当 <code>HTML</code> 解析到 <code>script</code> 标签的时候，会暂停构建 <code>DOM</code> ，完成后才会从暂停的地方重新开始。也就是说，如果想首屏渲染的越快，就越不应该在首屏就加载 <code>JS</code> 文件。并且 <code>CSS</code> 也会影响 <code>JS</code> 的执行，只有当解析完样式表才会执行 <code>JS</code> ，所以也可以认为这种情况下， <code>CSS</code> 也会暂停构建 <code>DOM</code>。</p>
<h4 id="Load-和-DOMContentLoaded-区别"><a href="#Load-和-DOMContentLoaded-区别" class="headerlink" title="Load 和 DOMContentLoaded 区别"></a>Load 和 DOMContentLoaded 区别</h4><ul>
<li><p><code>Load</code> 事件触发代表页面中的 <code>DOM</code>、<code>CSS</code>、<code>JS</code>、图片已经全部加载完毕。</p>
</li>
<li><p><code>DOMContentLoaded</code> 事件触发代表初始的 <code>HTML</code> 被完全加载和解析，不需要等待 <code>CSS</code>、<code>JS</code>、图片加载。</p>
</li>
</ul>
<h4 id="图层"><a href="#图层" class="headerlink" title="图层"></a>图层</h4><p>一般来说，可以把普通文档看成一个图层。特定的属性可以生成一个新的图层。不同的图层渲染互不影响，所以对于某些频繁需要渲染的建议单独生成一个新的图层，提高性能，但也不能生成过多的图层，会引起反作用。</p>
<p>通过以下几个常用属性可以生成新图层：</p>
<ul>
<li><strong>3D 转换：translate3d、translateZ</strong></li>
<li><strong>position：fixed</strong></li>
<li><strong>will-change</strong></li>
<li>video、iframe 标签</li>
<li>通过动画实现 opacity 动画转换</li>
</ul>
<h4 id="重绘（Repaint）和回流（Reflow）"><a href="#重绘（Repaint）和回流（Reflow）" class="headerlink" title="重绘（Repaint）和回流（Reflow）"></a>重绘（Repaint）和回流（Reflow）</h4><p>重绘和回流对于性能影响很大</p>
<ul>
<li>重绘是当节点需要改变外观而不会影响布局，比如改变 <code>color</code> 会发生重绘</li>
<li>回流是布局或几何属性需要改变就称为回流</li>
</ul>
<blockquote>
<p>回流必定发生重绘，重绘不一定会引发回流。回流所需的成本比重绘高得多</p>
</blockquote>
<p>以下几个动作可能会导致性能问题：</p>
<ul>
<li>改变 <code>window</code> 大小</li>
<li>改变字体</li>
<li>添加或删除样式</li>
<li>文字改变</li>
<li>定位或浮动</li>
<li>盒模型</li>
</ul>
<h4 id="减少重绘和回流"><a href="#减少重绘和回流" class="headerlink" title="减少重绘和回流"></a>减少重绘和回流</h4><ul>
<li>使用 <strong>translate</strong> 代替 top</li>
<li>使用 <strong>visibility</strong> 替换 display：none， 因为前者会重绘，后者会引发回流（改变了布局）</li>
<li>把 <strong>DOM 离线</strong>后修改，比如： 先把 DOM 给 display： none（会触发一次 Reflow），然后进行多次修改，然后再把它显示出来</li>
<li>避免使用 DOM 节点的属性值作为循环里的变量，可先获取属性值保存一下再循环</li>
<li>不要使用 table 布局，可能很小的改动就会造成整个 table 的重新布局</li>
<li>动画实现的速度选择，动画速度越快、回流次数越多，也可以选择使用 requestAnimationFrame</li>
<li>css 选择符从右往左匹配查找，避免 DOM 深度过深</li>
<li>将频繁运行的动画变为<strong>图层</strong>，图层能够阻止该节点回流影响别的元素，比如对于 video 标签，浏览器会自动将该节点变为图层</li>
</ul>
<h3 id="网路攻击"><a href="#网路攻击" class="headerlink" title="网路攻击"></a>网路攻击</h3><h4 id="XSS-攻击"><a href="#XSS-攻击" class="headerlink" title="XSS 攻击"></a><a href="http://47.98.159.95/my_blog/browser-security/001.html#%E4%BB%80%E4%B9%88%E6%98%AF-xss-%E6%94%BB%E5%87%BB%EF%BC%9F" target="_blank" rel="noopener">XSS 攻击</a></h4><h5 id="什么是-XSS-攻击？"><a href="#什么是-XSS-攻击？" class="headerlink" title="什么是 XSS 攻击？"></a>什么是 XSS 攻击？</h5><p><code>XSS</code> 是 <code>Cross Site Script</code> （即跨站脚本），为了和 <code>CSS</code> 区分，故叫它 <code>XSS</code>。<code>XSS</code> 攻击是指浏览器中执行恶意脚本（无论是跨域还是同域），从而拿到用户的信息并进行操作。</p>
<h5 id="XSS-攻击可能存在的危害"><a href="#XSS-攻击可能存在的危害" class="headerlink" title="XSS 攻击可能存在的危害"></a>XSS 攻击可能存在的危害</h5><ul>
<li>窃取 <code>Cookie</code></li>
<li>监听用户行为，比如输入账号密码后直接发送到黑客服务器</li>
<li>修改 <code>DOM</code> 伪造登录表单</li>
<li>在页面中生成浮窗广告</li>
</ul>
<h5 id="XSS-攻击实现的三种方式"><a href="#XSS-攻击实现的三种方式" class="headerlink" title="XSS 攻击实现的三种方式"></a>XSS 攻击实现的三种方式</h5><ul>
<li>存储型</li>
<li>反射型</li>
<li>文档型</li>
</ul>
<h6 id="存储型"><a href="#存储型" class="headerlink" title="存储型"></a>存储型</h6><p>存储型，就是将恶意脚本存储起来，存储型的 <code>XSS</code> 将脚本存储到了服务端的数据库，然后再客户端执行这些脚本，从而达到攻击的效果。</p>
<p>常见场景就是<strong>留言评论区</strong>提交一段脚本代码，如果后端没有做好转义的工作，那评论内容储存到了数据库，在页面渲染过程中直接执行了这段脚本代码。这就是存储型的 <code>XSS</code> 攻击。</p>
<h6 id="反射型"><a href="#反射型" class="headerlink" title="反射型"></a>反射型</h6><p>反射型，指恶意脚本作为网络请求的一部分。比如：</p>
<figure class="highlight"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">http://baidu.com?q=&lt;script&gt;alert("你完蛋了")&lt;/script&gt;</span><br></pre></td></tr></table></figure>
<p>服务端拿到 <code>q</code> 参数，然后将内容返回给浏览器端，浏览器将内容作为 <code>html</code> 的一部分解析，发现是一个脚本，直接执行然后就中招了。</p>
<p>反射型，顾名思义就是因为恶意脚本是通过作为网络请求的参数，经过服务器，然后再反射到 <code>html</code> 文档中，执行解析。和 存储型 不一样的是，服务器并没有存储这些恶意脚本。</p>
<h6 id="文档型"><a href="#文档型" class="headerlink" title="文档型"></a>文档型</h6><p>文档型 <code>XSS</code> 攻击并不会经过服务器，而是作为中间人的角色，在数据传输过程中劫持到网络数据包，然后修改里面的 <code>html</code> 文档。</p>
<p>这样的劫持方式包括 <code>WiFi</code> 路由器劫持 和本地恶意软件等</p>
<h5 id="防范措施"><a href="#防范措施" class="headerlink" title="防范措施"></a>防范措施</h5><p><code>XSS</code> 攻击都是让恶意脚本直接能在浏览器中执行。要防范它就是要避免这些脚本代码的执行。</p>
<h6 id="1-不要相信用户的输入"><a href="#1-不要相信用户的输入" class="headerlink" title="1. 不要相信用户的输入"></a>1. 不要相信用户的输入</h6><p>在前端或服务端，都要对用户的输入进行转码或过滤。如：</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="actionscript">alert(<span class="string">'你完蛋了'</span>)</span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p>转码为：</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&amp;lt;script&amp;gt;alert(&amp;#39;你完蛋了&amp;#39;)&amp;lt;/script&amp;gt;</span><br></pre></td></tr></table></figure>
<p>转码之后的代码在 <code>html</code> 解析过程中是无法执行的。</p>
<p>当然也可以利用关键词过滤的方式，直接将 <code>script</code> 标签删除。</p>
<h6 id="2-利用-CSP"><a href="#2-利用-CSP" class="headerlink" title="2. 利用 CSP"></a>2. 利用 CSP</h6><p><code>CSP</code>，是浏览器中的<strong>内容安全策略</strong>，他的<strong>核心就是服务器决定浏览器加载哪些资源</strong>，具体来说可以完成以下功能：</p>
<ol>
<li>限制其他域下的资源加载</li>
<li>禁止向其他域提交数据</li>
<li>提供上报机制，能帮助我们及时发现 <code>XSS</code> 攻击</li>
</ol>
<h6 id="3-利用-HttpOnly"><a href="#3-利用-HttpOnly" class="headerlink" title="3. 利用 HttpOnly"></a>3. 利用 HttpOnly</h6><p>很多 <code>XSS</code> 攻击脚本都是用来窃取 <code>Cookie</code>，而设置 <code>Cookie</code> 的 <code>HttpOnly</code> 属性后，<code>JavaScript</code> 便无法读取 <code>Cookie</code> 的值，这样也能很好的防范 <code>XSS</code> 攻击。</p>
<h5 id="总结-2"><a href="#总结-2" class="headerlink" title="总结"></a>总结</h5><p><code>XSS</code> 攻击是指浏览器中执行恶意脚本，然后拿到用户的信息进行操作。主要分为 存储型、反射型 和 文档型。</p>
<p>防范措施主要包括 不要信任用户的输入、利用 CSP 和 Cookie 的 HttpOnly 属性。</p>
<h4 id="CSRF-攻击"><a href="#CSRF-攻击" class="headerlink" title="CSRF 攻击"></a><a href="http://47.98.159.95/my_blog/browser-security/002.html#%E4%BB%80%E4%B9%88%E6%98%AFcsrf%E6%94%BB%E5%87%BB%EF%BC%9F" target="_blank" rel="noopener">CSRF 攻击</a></h4><h5 id="什么是-CSRF-攻击？"><a href="#什么是-CSRF-攻击？" class="headerlink" title="什么是 CSRF 攻击？"></a>什么是 CSRF 攻击？</h5><p><code>CSRF</code> （<code>Cross-site request forgery</code>），即跨站请求仿造，指的是黑客诱导用户点击链接，打开黑客的网站，然后黑客利用用户目前的登录状态发起跨站请求。</p>
<p>举例，在某个论坛点击了黑客精心挑选的小姐姐图片，你点击后，进入了一个新的页面，那可能就是被黑客攻击了。</p>
<p>怎么被攻击了呢？这点击发生了什么？可能会发生三件事，列举如：</p>
<ol>
<li>自动发 GET 请求</li>
</ol>
<p>黑客网页中可能有一段这样的代码：</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">img</span> <span class="attr">src</span>=<span class="string">"https://xxx.com/info?user=hhh&amp;count=100"</span>&gt;</span><span class="tag">&lt;/<span class="name">img</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p>利用 <code>img</code> 标签，进入网页后自动发送 GET 请求，值得注意的是，这个请求会自动带上关于 <code>xxx.com</code> 的 <code>cookie</code> 信息（这里假定你已经在 <code>xxx.com</code> 中登陆过）</p>
<p>假如服务端没有相应的验证机制，他可能认为发请求的是一个正常的用户，因为携带了相应的 <code>cookie</code> ，然后进行相应的各种操作，可以是转账汇款以及其他恶意操作。</p>
<ol start="2">
<li>自动发 POST 请求</li>
</ol>
<p>黑客可能自己填了一个表单，写了一段自动提交的脚本。</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">form</span> <span class="attr">id</span>=<span class="string">'hacker-form'</span> <span class="attr">action</span>=<span class="string">"https://xxx.com/info"</span> <span class="attr">method</span>=<span class="string">"POST"</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">"hidden"</span> <span class="attr">name</span>=<span class="string">"user"</span> <span class="attr">value</span>=<span class="string">"hhh"</span> /&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">"hidden"</span> <span class="attr">name</span>=<span class="string">"count"</span> <span class="attr">value</span>=<span class="string">"100"</span> /&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">form</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="javascript"><span class="built_in">document</span>.getElementById(<span class="string">'hacker-form'</span>).submit();</span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p>同样会携带相应的用户 <code>cookie</code> 信息，让服务器误认为是一个正常的用户在操作，让各种恶意的操作变为可能。</p>
<ol start="3">
<li>诱导点击发送 GET 请求</li>
</ol>
<p>在黑客网站上，可能会放上一个链接，驱使你点击：</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">a</span> <span class="attr">href</span>=<span class="string">"https://xxx/info?user=hhh&amp;count=100"</span> <span class="attr">taget</span>=<span class="string">"_blank"</span>&gt;</span>点击进入修仙世界<span class="tag">&lt;/<span class="name">a</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p>点击后，自动发送 <code>get</code> 请求，接下来和自动发 <code>get</code> 请求部分同理。</p>
<p>这就是 <code>CSRF</code> 攻击的原理。和 <code>XSS</code> 攻击对比，<code>CSRF</code> 攻击并不需要将恶意代码注入用户当前页面的 <code>html</code> 文档中，而是跳转到新的页面，利用服务器的验证漏洞和用户之前的登录状态来模拟用户进行操作。</p>
<h5 id="防范措施-1"><a href="#防范措施-1" class="headerlink" title="防范措施"></a>防范措施</h5><ol>
<li>利用 cookie 的 SameSite 属性</li>
</ol>
<p>CSRF 攻击中重要的一环就是自动发送目标站点下的 cookie ，然后就是这一份 Cookie 模拟了用户的身份。因此在 Cookie 上面下文章是防范的不二之选。</p>
<p>恰好，在 Cookie 当中有一个关键字段，可以对请求中的 cookie 的携带做一些限制，这个字段就是 SameSite。</p>
<p>SameSite 可以设置为三个值，Strict、Lax 和 None。</p>
<ul>
<li>Strict 模式下，浏览器完全禁止第三方请求携带 cookie。比如请求 baidu.com 只能在 baidu.com 域名当中的请求才能携带 cookie，在其他网站请求都不能。</li>
<li>在 Lax 模式下，就宽松些，但是只能在 get 方法提交表单或者 a 标签发送 get 请求的情况下可以携带 cookie，其他情况都不能。</li>
<li>在 None 模式下，也是默认模式，请求会自送携带上 cookie。</li>
</ul>
<ol start="2">
<li>验证来源站点</li>
</ol>
<p>这就需要用到请求头中的两个字段：Oringin 和 Refer。</p>
<p>Origin 只包含域名信息，而 Refer 包含了具体的 URL 路径。</p>
<p>但是这两者都是可以伪造的，通过 Ajax 中自定义请求头即可，安全性略差。</p>
<ol start="3">
<li>CSRF Token</li>
</ol>
<p>浏览器向服务器发送请求时，服务器生成一个字符串，将其植入到返回的页面中。</p>
<p>然后浏览器如果发送请求，就必须带上这个字符串，然后服务器来验证是否合法，如果不合法则不予相应，这个字符串就是 CSRF Token，通常第三方站点无法拿到这个 token，因此也就被服务器给拒绝。</p>
<h5 id="总结-3"><a href="#总结-3" class="headerlink" title="总结"></a>总结</h5><p>CSRF（Cross-site request forgery）即跨站请求伪造，指的是黑客诱导用户点击链接，打开黑客网站，然后黑客利用用户目前的登录状态发起跨站请求。</p>
<p>CSRF 攻击一般会有三种方式：</p>
<ul>
<li>自动 GET 请求</li>
<li>自动 POST 请求</li>
<li>诱导点击发送 GET 请求</li>
</ul>
<p>防范措施：利用 cookie 的 SameSite 属性、验证来源站点 和 CSRF Token。</p>
<h3 id="性能"><a href="#性能" class="headerlink" title="性能"></a><a href="https://yuchengkai.cn/docs/frontend/performance.html" target="_blank" rel="noopener">性能</a></h3><h4 id="网络相关"><a href="#网络相关" class="headerlink" title="网络相关"></a>网络相关</h4><h5 id="DNS-预解析"><a href="#DNS-预解析" class="headerlink" title="DNS 预解析"></a>DNS 预解析</h5><p>DNS 解析也是需要时间的，可以通过预解析的方式来预先获得域名所对应的的 IP。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&lt;link rel=<span class="string">"dns-prefetch"</span> href=<span class="string">"//xxx.com"</span> /&gt;</span><br></pre></td></tr></table></figure>
<h4 id="长列表性能优化"><a href="#长列表性能优化" class="headerlink" title="长列表性能优化"></a>长列表性能优化</h4><ol>
<li><p>分页处理，上拉加载（不可取）</p>
</li>
<li><p>使用 <code>requestAnimationFrame</code> 进行时间切片渲染加载 <code>dom</code>（适合列表项 <code>dom</code> 结构较简单的情况）</p>
</li>
<li><p>虚拟列表</p>
<ul>
<li>只对可见区域进行渲染，对非可见区域中的数据进行删除</li>
<li>一种方案可以使用监听 <code>scroll</code> 事件的方式来触发可视区域中数据的更新（频繁触发也会造成性能浪费问题）</li>
<li>另一种方案可以使用 <code>IntersectionObserver</code> 替代 <code>scroll</code> 事件，可以监听元素是否在可视区域内，在监听的事件中执行可是区域数据的更新（兼容性一般）</li>
<li>遗留问题：图片未完全加载时列表高度可能会改变，可以使用 <code>ResizeObserver</code> 来监听列表项内容区域高度，但兼容性不好</li>
</ul>
</li>
</ol>
<h4 id="v-for-为什么要加上-key-？"><a href="#v-for-为什么要加上-key-？" class="headerlink" title="v-for 为什么要加上 key ？"></a>v-for 为什么要加上 key ？</h4><p><code>key</code> 作为 <code>vue</code> 跟踪每个节点的身份唯一属性，从而重用和重新排序现有元素节点，而不用重新创建和删除操作，大大提高效率</p>
<h4 id="函数节流、防抖"><a href="#函数节流、防抖" class="headerlink" title="函数节流、防抖"></a>函数节流、防抖</h4><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 节流</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">throttle</span>(<span class="params">fn, delay</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">let</span> timer = <span class="literal">null</span></span><br><span class="line">    <span class="keyword">return</span> <span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">        <span class="keyword">if</span>(!timer) &#123;</span><br><span class="line">            timer = setTimerout(<span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">                fn.apply(<span class="keyword">this</span>, <span class="built_in">arguments</span>)</span><br><span class="line">                timer = <span class="literal">null</span></span><br><span class="line">            &#125;, delay)</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 防抖</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">debounce</span>(<span class="params">fn, delay</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">let</span> timer = <span class="literal">null</span></span><br><span class="line">    <span class="keyword">return</span> <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">        <span class="keyword">if</span>(timer) clearTimeout(timer)</span><br><span class="line">        timer = setTimeout(<span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">            fn.apply(<span class="keyword">this</span>, <span class="built_in">arguments</span>)</span><br><span class="line">            timer = <span class="literal">null</span></span><br><span class="line">        &#125;, delay)</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h4 id="二分法搜索"><a href="#二分法搜索" class="headerlink" title="二分法搜索"></a>二分法搜索</h4><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 有序数组的查找</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">binarySearch</span>(<span class="params">arr, value</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">var</span> low = <span class="number">0</span></span><br><span class="line">    <span class="keyword">var</span> high = arr.length - <span class="number">1</span></span><br><span class="line">    <span class="keyword">while</span>(low &lt; high) &#123;</span><br><span class="line">        <span class="keyword">var</span> mid = <span class="built_in">Math</span>.floor((low + high) / <span class="number">2</span>)</span><br><span class="line">        <span class="keyword">if</span> (value === arr[mid]) &#123;</span><br><span class="line">            <span class="keyword">return</span> mid</span><br><span class="line">        &#125; <span class="keyword">else</span> <span class="keyword">if</span> (value &gt; arr[mid]) &#123;</span><br><span class="line">            low = mid + <span class="number">1</span></span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            high = mid - <span class="number">1</span></span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> <span class="number">-1</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h4 id="二叉树的遍历"><a href="#二叉树的遍历" class="headerlink" title="二叉树的遍历"></a>二叉树的遍历</h4><h3 id="计算机"><a href="#计算机" class="headerlink" title="计算机"></a><a href="https://yuchengkai.cn/docs/cs/" target="_blank" rel="noopener">计算机</a></h3><h4 id="网络"><a href="#网络" class="headerlink" title="网络"></a>网络</h4><p>UDP</p>
<p>TCP</p>
<p>HTTP</p>
<p>HTTPS</p>
<p>HTTPS2.0</p>
<p>DNS</p>
<h4 id="从输入-URL-到页面加载完成的过程"><a href="#从输入-URL-到页面加载完成的过程" class="headerlink" title="从输入 URL 到页面加载完成的过程"></a>从输入 URL 到页面加载完成的过程</h4><ol>
<li>进行地址解析，解析出字符串地址中的主机、域名、端口号、参数等</li>
<li>根据解析出的域名进行 <code>DNS</code> 解析<ol>
<li>首先在浏览器中查找 <code>DNS</code> 缓存是否有对应的 <code>ip</code> 地址，如果有就直接使用</li>
<li>在操作系统中查找 <code>DNS</code> 缓存是否有对应的 <code>ip</code> 地址，如果有就直接使用</li>
<li>向本地 <code>DNS</code> 服务商发送请求查找 <code>DNS</code> 对应的 <code>ip</code> 地址</li>
<li>仍然没有的话就最后向 <code>Root Server</code> 根服务商（<code>com</code>）查询</li>
</ol>
</li>
<li>根据查询到的 <code>ip</code> 地址寻找目标服务器<ol>
<li>三次握手建立连接</li>
<li>寻找对应请求传输数据</li>
<li>四次挥手断开连接</li>
</ol>
</li>
<li>浏览器接受到响应码开始处理</li>
<li>浏览器开始渲染 <code>DOM</code>、<code>CSSOM</code>，合成 <code>Render Tree</code>，计算元素几何位置，最后渲染到屏幕</li>
</ol>
<h4 id="http-状态码"><a href="#http-状态码" class="headerlink" title="http 状态码"></a>http 状态码</h4><ul>
<li><strong>101</strong>： 切换协议，比如切换到 <code>websocket</code></li>
<li><strong>301</strong>： 永久重定向</li>
<li>302： 临时重定向</li>
<li><strong>304</strong>： 资源未修改，复用缓存资源</li>
<li>401： 请求要求用户身份认证</li>
<li><strong>403</strong>： 拒绝执行请求</li>
<li><strong>500</strong>： 服务器内部错误</li>
<li><strong>503</strong>： 服务器过载，无法处理请求</li>
</ul>
<h4 id="http1-0-和-http1-1-区别"><a href="#http1-0-和-http1-1-区别" class="headerlink" title="http1.0 和 http1.1 区别"></a>http1.0 和 http1.1 区别</h4><ul>
<li><strong>缓存处理</strong>：<ul>
<li><code>http1.0</code> 中主要使用 <code>header</code> 里的 <code>If-Modified-Since</code>、<code>Expires</code> 做缓存判断；- </li>
<li><code>http1.1</code> 则加入了更多的缓存控制策略：<code>Entity tag</code>、<code>If-Unmodified-Since</code>、<code>If-Match</code>、<code>If-None-Match</code> 等</li>
</ul>
</li>
<li><strong>带宽优化及网络连接的使用</strong><ul>
<li><code>http1.0</code> 存在浪费带宽现象，例如客户端只需要某个对象的一部分，服务端却将整个对象送过来，并且不支持断点续传功能</li>
<li><code>http1.1</code> 则在请求头引入了 <code>range</code> 头域，允许之请求资源的某部分，返回状态码是 <code>206</code></li>
</ul>
</li>
<li><p><strong>默认长连接</strong></p>
<ul>
<li><code>http1.1</code> 支持长连接和请求流水线处理，在一个 <code>tcp</code> 连接上可以传送多个 <code>http</code> 请求和响应，减少了建立和关闭连接的消耗和延迟，在 <code>http1.1</code> 中默认开启 <code>Connection: keep-alive</code> ，一定程度上弥补了 <code>http1.0</code> 每次请求都要创建连接的缺点</li>
</ul>
</li>
<li><p><strong>错误通知处理</strong></p>
</li>
<li><strong>Host 头处理</strong></li>
</ul>
<h4 id="http-和-https-的区别"><a href="#http-和-https-的区别" class="headerlink" title="http 和 https 的区别"></a>http 和 https 的区别</h4><ul>
<li><code>https</code> 需要到 <code>CA</code> 申请证书，一般免费的证书较少，因而需要一定的费用</li>
<li><code>http</code> 协议运行在 <code>tcp</code> 之上，明文传输；<code>https</code> 运行在 <code>SSL/TLS</code> 之上，<code>SSL/TLS</code> 运行在 <code>tcp</code> 之上，加密传输</li>
<li><code>http</code> 默认端口 <code>80</code>，<code>https</code> 默认端口 <code>443</code></li>
<li><code>https</code> 可以有效防劫持</li>
</ul>
<h4 id="前端缓存"><a href="#前端缓存" class="headerlink" title="前端缓存"></a>前端缓存</h4><ul>
<li>强缓存（不需要发起请求查询，首先检查强缓存）</li>
<li>协商缓存（需要发起请求查询）</li>
<li>缓存位置</li>
</ul>
<h5 id="强缓存"><a href="#强缓存" class="headerlink" title="强缓存"></a>强缓存</h5><ul>
<li><strong>Expires（http1.0）</strong>：即过期时间，告诉浏览器过期之前都可以从缓存中获取数据，不用重新发起请求，但可能前后端时间不一致导致缓存失败</li>
<li><strong>Cache-Control（http1.1）</strong>：过期时长<ul>
<li><code>max-age=3600</code></li>
<li><code>public</code>： 客户端与代理服务器均缓存</li>
<li><code>private</code>： 仅客户端缓存</li>
<li><code>no-cache</code>： 跳过当前强缓存，进入协商缓存</li>
<li><code>no-store</code>： 不缓存</li>
<li><code>s-maxage</code>：代理服务器的缓存时间</li>
<li><code>must-revalidate</code>： 缓存一旦过期，则回到源服务器验证</li>
</ul>
</li>
</ul>
<h5 id="协商缓存"><a href="#协商缓存" class="headerlink" title="协商缓存"></a>协商缓存</h5><ul>
<li><strong>Last-Modified</strong>： 最后的修改时间，由服务器在响应头中加上此字段给浏览器，如果浏览器再次请求此资源，则会在请求头中携带 <strong>If-Modified-Since</strong> 字段，此字段为服务器传来的最后的修改时间，服务器拿到该时间后会与服务器中这个时间做对比，判断是否需要返回新资源或 <code>304</code></li>
<li><strong>ETag</strong>： 服务器根据资源内容生成的唯一标志，只要里面内容有改动则会变，服务器通过响应头把这个值返回给浏览器。浏览器再次请求该资源时，会将该值放在请求头中携带 <strong>If-None-Match</strong> 字段，服务器根据这个值判断是否需要返回新资源或 <code>304</code></li>
<li><strong>两者对比</strong>：<code>Etag</code> 精度高，但性能不佳，两者都支持的情况下，服务器优先考虑 <code>ETag</code></li>
</ul>
<h5 id="缓存位置"><a href="#缓存位置" class="headerlink" title="缓存位置"></a>缓存位置</h5><ul>
<li>Service Worker（<strong>离线缓存</strong>就是 <strong>Service Worker Cache</strong>）</li>
<li>Memory Cache（小的 js、css 文件缓存进内存，大的文件进磁盘）</li>
<li>Disk Cache（内存使用率较高时，文件优先进入磁盘）</li>
<li>Push Cache（http2 推送缓存）</li>
</ul>
<h5 id="总结-4"><a href="#总结-4" class="headerlink" title="总结"></a>总结</h5><ul>
<li>首先通过 <code>Cache-Control</code> 验证强缓存是否可用</li>
<li>强缓存可用，直接使用</li>
<li>否则进入协商缓存，即发送 <code>http</code> 请求，服务器通过请求头中的 <code>If-Modified-Since</code> 和 <code>If-None-Match</code> 这些条件请求字段检查资源是否更新</li>
<li>若资源更新，则返回资源和 <code>200</code> 状态码</li>
<li>否则，返回 <code>304</code> 状态码，告诉浏览器直接从缓存中获取资源</li>
</ul>
<h4 id="简述三次握手四次挥手"><a href="#简述三次握手四次挥手" class="headerlink" title="简述三次握手四次挥手"></a>简述三次握手四次挥手</h4><h5 id="三次握手"><a href="#三次握手" class="headerlink" title="三次握手"></a>三次握手</h5><ol>
<li>客户端向服务端发起连接询问</li>
<li>服务端回应客户端可连接</li>
<li>客户端回应服务端收到可连接的回应，至此建立连接</li>
</ol>
<p><strong>？为什么不是两次？</strong></p>
<blockquote>
<p> 根本原因是无法确认客户端的接受能力。</p>
</blockquote>
<p>如果是两次，客户端第一次发起连接询问，由于网络原因滞留在了网络中，迟迟没有到达服务端，此时 <code>tcp</code> 以为丢包了，于是重发，两次握手建立了连接，传输数据后关闭连接。</p>
<p>但是此时滞留网络中的第一次询问到达了服务端，由于是两次握手，此时服务端没有确认客户端的接受能力，就默认建立了连接，但是客户端此时早已断开了连接，从而导致服务端连接资源的浪费，所以至少需要三次握手</p>
<h5 id="四次挥手"><a href="#四次挥手" class="headerlink" title="四次挥手"></a>四次挥手</h5><ol>
<li>客户端向服务端发起断开连接请求</li>
<li>服务端回应客户端，已收到断开请求，但并未确认可以断开连接，此时服务端可能仍有数据向客户端发送</li>
<li>服务端数据发完，服务端向客户端发送确认可以断开连接</li>
<li>客户端回应服务端确认断开连接</li>
</ol>
<p><strong>？为什么不是三次？</strong></p>
<p>如果将第 2 和第 3 步合并，此时长时间的延迟会导致客户端误以为服务端没有收到第 1 步的断开请求，从而导致客户端不断重发第 1 步</p>
<h3 id="数据结构"><a href="#数据结构" class="headerlink" title="数据结构"></a>数据结构</h3><h4 id="栈"><a href="#栈" class="headerlink" title="栈"></a>栈</h4><p>栈的特点： 先进后出</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Stack</span> </span>&#123;</span><br><span class="line">    <span class="keyword">constructor</span>() &#123;</span><br><span class="line">        <span class="keyword">this</span>.items = []</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// 入栈</span></span><br><span class="line">    push(ele) &#123;</span><br><span class="line">        <span class="keyword">this</span>.items.push(ele)</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// 出栈</span></span><br><span class="line">    pop() &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">this</span>.items.pop()</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// 末尾</span></span><br><span class="line">    peek() &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">this</span>.items[<span class="keyword">this</span>.items.length - <span class="number">1</span>]</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// 是否空栈</span></span><br><span class="line">    isEmpty() &#123;</span><br><span class="line">        <span class="keyword">return</span> !<span class="keyword">this</span>.items.length</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// 长度</span></span><br><span class="line">    size() &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">this</span>.items.length</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// 清空</span></span><br><span class="line">    clear() &#123;</span><br><span class="line">        <span class="keyword">this</span>.items = []</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h4 id="队列"><a href="#队列" class="headerlink" title="队列"></a>队列</h4><p>先进先出</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Queue</span>() </span>&#123;</span><br><span class="line">    <span class="keyword">constructor</span>() &#123;</span><br><span class="line">        <span class="keyword">this</span>.items = []</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// 入队</span></span><br><span class="line">    enqueue(ele) &#123;</span><br><span class="line">        <span class="keyword">this</span>.items.push(ele)</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// 出队</span></span><br><span class="line">    dequeue() &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">this</span>.items.shift()</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// 队头</span></span><br><span class="line">    front() &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">this</span>.items[<span class="number">0</span>]</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// 清空队列</span></span><br><span class="line">    clear() &#123;</span><br><span class="line">        <span class="keyword">this</span>.items = []</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// 队列大小</span></span><br><span class="line">    size() &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">this</span>.items.length</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// 是否为空</span></span><br><span class="line">    isEmpty() &#123;</span><br><span class="line">        <span class="keyword">return</span> !<span class="keyword">this</span>.items.length</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// 打印输出</span></span><br><span class="line">    print() &#123;</span><br><span class="line">        <span class="built_in">console</span>.log(<span class="keyword">this</span>.items.toString())</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h4 id="链表"><a href="#链表" class="headerlink" title="链表"></a>链表</h4><h4 id="树"><a href="#树" class="headerlink" title="树"></a>树</h4><h3 id="算法"><a href="#算法" class="headerlink" title="算法"></a>算法</h3><h4 id="冒泡排序"><a href="#冒泡排序" class="headerlink" title="冒泡排序"></a>冒泡排序</h4><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">sort</span>(<span class="params">arr</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">var</span> tmp = <span class="number">0</span></span><br><span class="line">    <span class="keyword">for</span>(<span class="keyword">var</span> i = <span class="number">0</span>; i &lt; arr.length; i++) &#123;</span><br><span class="line">        <span class="keyword">for</span>(<span class="keyword">var</span> j = <span class="number">0</span>; j &lt; arr.length - i - <span class="number">1</span>; j++) &#123;</span><br><span class="line">            <span class="keyword">if</span>(arr[j] &gt; arr[j + <span class="number">1</span>]) &#123;</span><br><span class="line">                tmp = arr[i]</span><br><span class="line">                arr[i] = arr[j + <span class="number">1</span>]</span><br><span class="line">                arr[j + <span class="number">1</span>] = tmp</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h5 id="冒泡优化–元素交换标志"><a href="#冒泡优化–元素交换标志" class="headerlink" title="冒泡优化–元素交换标志"></a>冒泡优化–元素交换标志</h5><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">sort</span>(<span class="params">arr</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">var</span> tmp = <span class="number">0</span></span><br><span class="line">    <span class="keyword">for</span>(<span class="keyword">var</span> i = <span class="number">0</span>; i &lt; arr.length; i++) &#123;</span><br><span class="line">        <span class="keyword">var</span> isSorted = <span class="literal">true</span> <span class="comment">// 默认有序</span></span><br><span class="line">        <span class="keyword">for</span>(<span class="keyword">var</span> j = <span class="number">0</span>; j &lt; arr.length - i - <span class="number">1</span>; j++) &#123;</span><br><span class="line">            <span class="keyword">if</span>(arr[j] &gt; arr[j + <span class="number">1</span>]) &#123;</span><br><span class="line">                tmp = arr[j]</span><br><span class="line">                arr[j] = arr[j + <span class="number">1</span>]</span><br><span class="line">                arr[j + <span class="number">1</span>] = tmp</span><br><span class="line">                isSorted = <span class="literal">false</span> <span class="comment">// 发生元素交换，false</span></span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">// 如果没有发生元素交换，则结束循环</span></span><br><span class="line">        <span class="keyword">if</span>(isSorted) &#123;</span><br><span class="line">            <span class="keyword">break</span></span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h5 id="冒泡优化–无序边界"><a href="#冒泡优化–无序边界" class="headerlink" title="冒泡优化–无序边界"></a>冒泡优化–无序边界</h5><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">sort</span>(<span class="params">arr</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">var</span> tmp = <span class="number">0</span></span><br><span class="line">    <span class="keyword">var</span> lastExchangeIndex = <span class="number">0</span> <span class="comment">// 最后进行交换的元素位置</span></span><br><span class="line">    <span class="keyword">var</span> sortBorder = arr.length - <span class="number">1</span> <span class="comment">// 无序边界</span></span><br><span class="line">    <span class="keyword">for</span>(<span class="keyword">var</span> i = <span class="number">0</span>; i &lt; arr.length - <span class="number">1</span>; i++) &#123;</span><br><span class="line">        <span class="keyword">var</span> isSorted = <span class="literal">true</span> <span class="comment">// 元素交换标志</span></span><br><span class="line">        <span class="keyword">for</span>(<span class="keyword">var</span> j = <span class="number">0</span>; j &lt; sortBorder; j++) &#123;</span><br><span class="line">            <span class="keyword">if</span>(arr[j] &gt; arr[j + <span class="number">1</span>]) &#123;</span><br><span class="line">                tmp = arr[j]</span><br><span class="line">                arr[j] = arr[j + <span class="number">1</span>]</span><br><span class="line">                arr[j + <span class="number">1</span>] = tmp</span><br><span class="line">                isSorted = <span class="literal">false</span> <span class="comment">// 元素发生了交换</span></span><br><span class="line">                lastExchangeIndex = j</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        sortderBorder = lastExchangeIndex <span class="comment">// 无序边界</span></span><br><span class="line">        <span class="comment">// 有序了则退出循环</span></span><br><span class="line">        <span class="keyword">if</span>(isSorted) &#123;</span><br><span class="line">            <span class="keyword">break</span></span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h5 id="冒泡优化–鸡尾酒排序"><a href="#冒泡优化–鸡尾酒排序" class="headerlink" title="冒泡优化–鸡尾酒排序"></a>冒泡优化–鸡尾酒排序</h5><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">sort</span>(<span class="params">arr</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">var</span> tmp = <span class="number">0</span></span><br><span class="line">    <span class="keyword">for</span>(<span class="keyword">var</span> i = <span class="number">0</span>; i &lt; arr.length / <span class="number">2</span>; i++) &#123;</span><br><span class="line">        <span class="keyword">var</span> isSorted = <span class="literal">true</span> <span class="comment">// 默认有序</span></span><br><span class="line">        <span class="comment">// 从左往右</span></span><br><span class="line">        <span class="keyword">for</span>(<span class="keyword">var</span> j = <span class="number">0</span>; j &lt; arr.length - i - <span class="number">1</span>; j++) &#123;</span><br><span class="line">            <span class="keyword">if</span>(arr[j] &gt; arr[j + <span class="number">1</span>]) &#123;</span><br><span class="line">                tmp = arr[j]</span><br><span class="line">                arr[j] = arr[j + <span class="number">1</span>]</span><br><span class="line">                arr[j + <span class="number">1</span>] = tmp</span><br><span class="line">                isSorted = <span class="literal">false</span></span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span>(isSorted) &#123;</span><br><span class="line">            <span class="keyword">break</span></span><br><span class="line">        &#125;</span><br><span class="line">        isSorted = <span class="literal">true</span> <span class="comment">// 重置标志</span></span><br><span class="line">        <span class="comment">// 从右往左</span></span><br><span class="line">        <span class="keyword">for</span>(j = arr.length - i - <span class="number">1</span>; j &gt; i; j--) &#123;</span><br><span class="line">            <span class="keyword">if</span>(arr[j] &lt; arr[j - <span class="number">1</span>]) &#123;</span><br><span class="line">                tmp = arr[j]</span><br><span class="line">                arr[j] = arr[j - <span class="number">1</span>]</span><br><span class="line">                arr[j - <span class="number">1</span>] = tmp</span><br><span class="line">                isSorted = <span class="literal">false</span> </span><br><span class="line">            &#125; </span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span>(isSorted) &#123;</span><br><span class="line">            <span class="keyword">break</span></span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h4 id="斐波那契数列"><a href="#斐波那契数列" class="headerlink" title="斐波那契数列"></a>斐波那契数列</h4><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">fibonacci</span>(<span class="params">n</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">if</span>(n === <span class="number">1</span> || n === <span class="number">2</span>) <span class="keyword">return</span> <span class="number">1</span></span><br><span class="line">    <span class="keyword">return</span> fibonacci(n - <span class="number">1</span>) + fibonacci(n - <span class="number">2</span>)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="js题目"><a href="#js题目" class="headerlink" title="js题目"></a>js题目</h3><h4 id="1-考察原型链"><a href="#1-考察原型链" class="headerlink" title="1. 考察原型链"></a>1. 考察原型链</h4><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> o = <span class="built_in">Object</span>.create(&#123;<span class="attr">x</span>:<span class="number">1</span>,<span class="attr">y</span>:<span class="number">2</span>&#125;)</span><br><span class="line">o.z = <span class="number">3</span></span><br><span class="line"><span class="keyword">let</span> &#123;x, ...newObj&#125; = o</span><br><span class="line"><span class="keyword">let</span> &#123;y, z&#125; = newObj</span><br><span class="line">x <span class="comment">// 1</span></span><br><span class="line">y <span class="comment">// undefined</span></span><br><span class="line">z <span class="comment">// 3</span></span><br></pre></td></tr></table></figure>
<h4 id="2-考察this指向"><a href="#2-考察this指向" class="headerlink" title="2. 考察this指向"></a>2. 考察this指向</h4><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> a = <span class="number">10</span></span><br><span class="line"><span class="keyword">var</span> obj = &#123;</span><br><span class="line">	a:<span class="number">20</span>,</span><br><span class="line">	fun: <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">		<span class="keyword">var</span> a = <span class="number">30</span></span><br><span class="line">		<span class="built_in">console</span>.log(<span class="keyword">this</span>.a)</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br><span class="line">setTimeout(obj.fun, <span class="number">100</span>) <span class="comment">// 10</span></span><br><span class="line">obj.fun() <span class="comment">// 20</span></span><br></pre></td></tr></table></figure>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> obj1 = &#123;</span><br><span class="line">  name: <span class="string">'obj1_name'</span>,</span><br><span class="line">  print: <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="function"><span class="params">()</span> =&gt;</span> <span class="built_in">console</span>.log(<span class="keyword">this</span>.name)</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">let</span> obj2 = &#123; <span class="attr">name</span>: <span class="string">'obj2_name'</span> &#125;</span><br><span class="line">obj1.print()() <span class="comment">// 'obj1_name'</span></span><br><span class="line">obj1.print().call(obj2) <span class="comment">// 'obj1_name'</span></span><br><span class="line">obj1.print.call(obj2)() <span class="comment">// 'obj2_name'</span></span><br></pre></td></tr></table></figure>
<blockquote>
<p>obj1.print()() 中 this 指向 obj1；</p>
<p>obj1.print().call(obj2) 中 call 给箭头函数绑定 this 是没有用的；</p>
<p>obj1.print.call(obj2)() 中先使用 call 改变了 this 指向 obj2。</p>
</blockquote>
<h4 id="3-JS-数据类型概念"><a href="#3-JS-数据类型概念" class="headerlink" title="3. JS 数据类型概念"></a>3. <code>JS</code> 数据类型概念</h4><ol>
<li><code>js</code> 原始数据类型有哪些？引用数据类型有哪些？</li>
</ol>
<p>原始数据类型：</p>
<ul>
<li><code>boolean</code></li>
<li><code>number</code></li>
<li><code>string</code></li>
<li><code>null</code></li>
<li><code>undefined</code></li>
<li><code>symbol</code></li>
</ul>
<p>引用数据类型：</p>
<ul>
<li><code>Object</code><ul>
<li><code>Array</code></li>
<li><code>RegExp</code></li>
<li><code>Date</code></li>
<li><code>Math</code></li>
<li><code>Function</code></li>
</ul>
</li>
</ul>
<ol start="2">
<li>函数参数</li>
</ol>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">test</span>(<span class="params">person</span>) </span>&#123;</span><br><span class="line">    person.age = <span class="number">22</span></span><br><span class="line">    person = &#123;</span><br><span class="line">        name: <span class="string">'inner'</span>,</span><br><span class="line">        age: <span class="number">33</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> person</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">const</span> p1 = &#123;</span><br><span class="line">    name: <span class="string">'outer'</span>,</span><br><span class="line">    age: <span class="number">11</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">const</span> p2 = test(p1)</span><br><span class="line">p1 <span class="comment">// &#123; name: 'outer', age: 22 &#125;</span></span><br><span class="line">p2 <span class="comment">// &#123; name: 'inner', age: 33 &#125;</span></span><br></pre></td></tr></table></figure>
<blockquote>
<p>原因：在传参给函数的时候传递的是参数在堆内存中的内存地址值，test 函数中的实参 person 是 p1 对象的内存地址，通过 person.age = 22 改变的确实是 p1 的值，但随后 person 变成了另一块内存空间地址，并且在最后将这另外一份内存空间的地址返回，赋给了 p2。</p>
</blockquote>
<h4 id="4-闭包与作用域链"><a href="#4-闭包与作用域链" class="headerlink" title="4. 闭包与作用域链"></a>4. 闭包与作用域链</h4><p>考察闭包与作用域链，详见<a href="https://github.com/mqyqingfeng/Blog/issues/9" target="_blank" rel="noopener">博客</a></p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> data = [];</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> (<span class="keyword">var</span> i = <span class="number">0</span>; i &lt; <span class="number">3</span>; i++) &#123;</span><br><span class="line">  data[i] = <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span><br><span class="line">    <span class="built_in">console</span>.log(i);</span><br><span class="line">  &#125;;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">data[<span class="number">0</span>]();</span><br><span class="line">data[<span class="number">1</span>]();</span><br><span class="line">data[<span class="number">2</span>]();</span><br></pre></td></tr></table></figure>
<p>区别</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> data = [];</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> (<span class="keyword">var</span> i = <span class="number">0</span>; i &lt; <span class="number">3</span>; i++) &#123;</span><br><span class="line">  data[i] = (<span class="function"><span class="keyword">function</span> (<span class="params">i</span>) </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">            <span class="built_in">console</span>.log(i);</span><br><span class="line">        &#125;</span><br><span class="line">  &#125;)(i);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">data[<span class="number">0</span>]();</span><br><span class="line">data[<span class="number">1</span>]();</span><br><span class="line">data[<span class="number">2</span>]();</span><br></pre></td></tr></table></figure>
<h4 id="5-非匿名的立即执行函数"><a href="#5-非匿名的立即执行函数" class="headerlink" title="5. 非匿名的立即执行函数"></a>5. <a href="https://yuchengkai.cn/docs/frontend/#%E6%89%A7%E8%A1%8C%E4%B8%8A%E4%B8%8B%E6%96%87" target="_blank" rel="noopener">非匿名的立即执行函数</a></h4><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> foo = <span class="number">1</span></span><br><span class="line">(<span class="function"><span class="keyword">function</span> <span class="title">foo</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">    foo = <span class="number">10</span></span><br><span class="line">    <span class="built_in">console</span>.log(foo)</span><br><span class="line">&#125;()) <span class="comment">// -&gt; ƒ foo() &#123; foo = 10 ; console.log(foo) &#125;</span></span><br></pre></td></tr></table></figure>
<p>当 <code>JS</code> 解析器在遇到<strong>非匿名的立即执行函数</strong>时，会创建一个<strong>辅助的特定对象</strong>，然后将函数名作为这个对象的属性，因此函数内部才可以访问到 <code>foo</code> ，但是这个值又是<strong>只读</strong>的，所以对它赋值并不生效，所以打印结果还是这个函数，并且外部的值也没有发生更改</p>
<h4 id="6-ES6-多维数组降维"><a href="#6-ES6-多维数组降维" class="headerlink" title="6. ES6 多维数组降维"></a>6. <a href="https://yuchengkai.cn/docs/frontend/#map%E3%80%81flatmap-%E5%92%8C-reduce" target="_blank" rel="noopener">ES6 多维数组降维</a></h4><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> flattenDeep = <span class="function">(<span class="params">arr</span>) =&gt;</span> <span class="built_in">Array</span>.isArray(arr)</span><br><span class="line">	? arr.reduce(<span class="function">(<span class="params">a, b</span>) =&gt;</span> [...a, ...flattenDeep(b)], [])</span><br><span class="line">	: [arr]</span><br><span class="line"></span><br><span class="line">flattenDeep([<span class="number">1</span>, [[<span class="number">2</span>], [<span class="number">3</span>, [<span class="number">4</span>]], <span class="number">5</span>]])</span><br></pre></td></tr></table></figure>
<h4 id="7-for-in-和-for-of-的区别"><a href="#7-for-in-和-for-of-的区别" class="headerlink" title="7. for in 和 for of 的区别"></a>7. for in 和 for of 的区别</h4><ul>
<li><p><code>for...in</code> 可以遍历数组的键名。只遍历可枚举属性，<strong>包括原型链上的可枚举属性</strong>，常用于遍历 <code>object</code>。</p>
</li>
<li><p><code>for...of</code> 是 <code>ES6</code> 用作遍历所有数据结构的<strong>统一的方法</strong>，一个数据结构只要部署了 <strong>Symbol.iterator</strong> 属性，就被视为具备 <code>iterator</code> 接口，就可以使用 <code>for...of</code> 循环遍历他的成员，具备 <code>iterator</code> 接口的数据类型包括<strong>数组、Set、Map、arguments、DOM NodeList对象、generator对象和字符串</strong></p>
</li>
</ul>
<h4 id="8-和"><a href="#8-和" class="headerlink" title="8. [] == ![] 和 {} == !{}"></a>8. [] == ![] 和 {} == !{}</h4><p>高程中有关于 <code>==</code> 的隐式转换</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">[] == ![] <span class="comment">// true</span></span><br></pre></td></tr></table></figure>
<ul>
<li><code>[]</code> 是引用类型，以上比较的是栈地址的比较</li>
<li><code>!</code> 先运算，<code>!</code> 可以将 <code>null</code>、<code>undefined</code>、<code>NaN</code> 以及 空串 取反，为 <code>true</code>，其余都为 <code>false</code>，故 <code>![]</code> 是 <code>false</code> </li>
<li>此时运算结果为 <code>[] == false</code>，相当于 <code>[] == 0</code></li>
<li><code>[]</code> 不是一个基本数据类型，通过对象的 <code>valueOf</code> 方法得到该对象的基本类型值，如果没有 <code>valueOf</code> 方法则使用 <code>toString</code> 方法，调用 <code>toString</code> 得到 <code>&#39;&#39;</code> 空字符串</li>
<li>空字符串最终会转换成数值类型，即 <code>0</code>，所以最终结果是 <code>0 == 0</code></li>
</ul>
<p>而 <code>{} == !{}</code> 也一样，但是 <code>{}.toString()</code> 的结果是 <code>NaN</code>，任何数跟 <code>NaN</code> 比较都是 <code>false</code>，故 <code>{} == !{}</code> 结果为 <code>false</code></p>
<h4 id="9-js-函数"><a href="#9-js-函数" class="headerlink" title="9. js 函数"></a>9. js 函数</h4><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">Foo</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">  getName = <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123; <span class="built_in">console</span>.log(<span class="number">1</span>); &#125;;</span><br><span class="line">  <span class="keyword">return</span> <span class="keyword">this</span></span><br><span class="line">&#125;</span><br><span class="line">Foo.getName = <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123; <span class="built_in">console</span>.log(<span class="number">2</span>); &#125;;</span><br><span class="line">Foo.prototype.getName = <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123; <span class="built_in">console</span>.log(<span class="number">3</span>); &#125;;</span><br><span class="line"><span class="keyword">var</span> getName = <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123; <span class="built_in">console</span>.log(<span class="number">4</span>); &#125;;</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">getName</span>(<span class="params"></span>) </span>&#123; <span class="built_in">console</span>.log(<span class="number">5</span>); &#125;;</span><br><span class="line"></span><br><span class="line">Foo.getName(); <span class="comment">// 2</span></span><br><span class="line">getName(); <span class="comment">// 4</span></span><br><span class="line">Foo().getName(); <span class="comment">// 1</span></span><br><span class="line">getName(); <span class="comment">// 1</span></span><br><span class="line"><span class="keyword">new</span> Foo.getName(); <span class="comment">// 2</span></span><br><span class="line"><span class="keyword">new</span> Foo().getName(); <span class="comment">// 3</span></span><br><span class="line"><span class="keyword">new</span> <span class="keyword">new</span> Foo().getName(); <span class="comment">// 3</span></span><br></pre></td></tr></table></figure>
<h4 id="10-promise-输出顺序问题"><a href="#10-promise-输出顺序问题" class="headerlink" title="10. promise 输出顺序问题"></a>10. promise 输出顺序问题</h4><h5 id="注意："><a href="#注意：" class="headerlink" title="注意："></a>注意：</h5><ul>
<li><code>new Promise</code> 中的代码是<strong>同步执行</strong>的</li>
<li><code>then</code> 回调中代码会注册到<strong>微任务</strong>队列中等待执行</li>
<li>多个 <code>then</code> 的链式调用中，下一个 <code>then</code> 依赖于上一个 <code>then</code> 执行返回的结果，即上一个 <code>then</code> 的执行完毕之后，下一个 <code>then</code> 才开始注册，但还没有开始执行</li>
<li>异步任务的注册与执行是两码事，注册不是执行</li>
</ul>
<h5 id="理解一下题目"><a href="#理解一下题目" class="headerlink" title="理解一下题目"></a>理解一下题目</h5><h6 id="Promise-注册微任务和执行过程"><a href="#Promise-注册微任务和执行过程" class="headerlink" title="Promise 注册微任务和执行过程"></a><a href="https://mp.weixin.qq.com/s/op3EaSXKTCXwYt_uRvhePg" target="_blank" rel="noopener">Promise 注册微任务和执行过程</a></h6><h4 id="数组去重"><a href="#数组去重" class="headerlink" title="数组去重"></a>数组去重</h4><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> arr = [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">5</span>, <span class="number">5</span>, <span class="number">6</span>, <span class="number">1</span>, <span class="number">2</span>, <span class="number">9</span>, <span class="number">3</span>]</span><br></pre></td></tr></table></figure>
<ol>
<li>利用 Set</li>
</ol>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> unique = <span class="function"><span class="params">arr</span> =&gt;</span> [...new <span class="built_in">Set</span>(arr)]</span><br></pre></td></tr></table></figure>
<ol start="2">
<li>filter &amp;&amp; indexOf</li>
</ol>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> unique = <span class="function"><span class="params">arr</span> =&gt;</span> &#123;</span><br><span class="line">  <span class="keyword">return</span> arr.filter(<span class="function">(<span class="params">item, index</span>) =&gt;</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> arr.indexOf(item) === index</span><br><span class="line">  &#125;)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<ol start="3">
<li>map</li>
</ol>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> unique = <span class="function"><span class="params">arr</span> =&gt;</span> &#123;</span><br><span class="line">  <span class="keyword">let</span> map = <span class="keyword">new</span> <span class="built_in">Map</span>()</span><br><span class="line">  <span class="keyword">return</span> arr.filter(<span class="function">(<span class="params">item, index</span>) =&gt;</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> !seen.has(item) &amp;&amp; seen.set(item, <span class="number">1</span>)</span><br><span class="line">  &#125;)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h4 id="运算符优先级"><a href="#运算符优先级" class="headerlink" title="运算符优先级"></a>运算符优先级</h4><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> val = <span class="string">'string'</span></span><br><span class="line"><span class="built_in">console</span>.log(<span class="string">'log is'</span> + (val === <span class="string">'string'</span>) ? <span class="string">'Yes'</span> : <span class="string">'No'</span>) <span class="comment">// Yes</span></span><br></pre></td></tr></table></figure>
<blockquote>
<p>这里由于 + 运算符优先级高于 ? ，实际上是 ‘log is true’ ? ‘Yes’ : ‘No’，故结果输出为 Yes</p>
</blockquote>
<h4 id="隐式定义全局变量"><a href="#隐式定义全局变量" class="headerlink" title="隐式定义全局变量"></a>隐式定义全局变量</h4><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">(<span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">  <span class="keyword">var</span> x = y = <span class="number">1</span></span><br><span class="line">&#125;)()</span><br><span class="line"><span class="built_in">console</span>.log(y) <span class="comment">// 1</span></span><br><span class="line"><span class="built_in">console</span>.log(x) <span class="comment">// ReferenceError</span></span><br></pre></td></tr></table></figure>
<blockquote>
<p>变量提升和隐式定义全局变量，在作用域内，变量定义和函数定义会先行提升，所以里面变成了 var x; y = 1; x = 1。这里有坑就是，只会在内部定义第一个变量 x，而 y 则由于没有通过 var 定义，所以隐式定义了一个全局变量 y，所以 y 在全局作用域下，而 x 在函数内部</p>
</blockquote>
<h3 id="ES6"><a href="#ES6" class="headerlink" title="ES6"></a>ES6</h3><h4 id="1-es6-新增的主要特性"><a href="#1-es6-新增的主要特性" class="headerlink" title="1. es6 新增的主要特性"></a>1. es6 新增的主要特性</h4><p>每一个都可单独展开讲</p>
<ol>
<li><code>let</code>、<code>const</code> （块级作用域）</li>
<li>箭头函数 （<code>this</code> 指向，不可 <code>new</code>，没有 <code>arguments</code>，没有原型）</li>
<li>模板字符串 <code></code></li>
<li>解构赋值 <code>...</code></li>
<li><code>for...of</code> 循环 （可遍历实现了 <code>iterator</code> 接口的对象）</li>
<li><code>import</code>、<code>export</code> 导入导出</li>
<li><code>set</code> 数据结构</li>
<li><code>...</code> 展开运算符</li>
<li>修饰器 <code>@</code></li>
<li><code>class</code> 类继承 （原型继承的语法糖）</li>
<li><code>async</code>、<code>await</code></li>
<li><code>promise</code> （原理，模拟实现 <code>promise</code>）</li>
<li><code>Symbol</code></li>
<li><code>Proxy</code> （<code>vue3</code> 核心实现）</li>
</ol>
<h3 id="Vue-js-常见题目"><a href="#Vue-js-常见题目" class="headerlink" title="Vue.js 常见题目"></a>Vue.js 常见题目</h3><h4 id="1-页面中定义一个定时器，在哪个阶段清除？"><a href="#1-页面中定义一个定时器，在哪个阶段清除？" class="headerlink" title="1. 页面中定义一个定时器，在哪个阶段清除？"></a>1. 页面中定义一个定时器，在哪个阶段清除？</h4><blockquote>
<p>答：在 beforeDestroy 中销毁定时器</p>
</blockquote>
<p><strong>原因：</strong>在页面 A 中开启的定时器，在进入 B 页面时，定时器仍在执行，这是非常消耗性能的</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 解决方法1</span></span><br><span class="line"><span class="comment">// 在 mounted 中开启定时器</span></span><br><span class="line">mounted() &#123;</span><br><span class="line">	<span class="keyword">this</span>.timer = setInterval(<span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">        <span class="built_in">console</span>.log(<span class="number">1</span>)</span><br><span class="line">    &#125;, <span class="number">1000</span>)</span><br><span class="line">&#125;,</span><br><span class="line"><span class="comment">// 在 beforeDestroy 中销毁定时器</span></span><br><span class="line">beforeDestroy() &#123;</span><br><span class="line">    clearInterval(<span class="keyword">this</span>.timer)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>本身这种方法没什么毛病，但是就是啰嗦，此时可以通过 $once 来实现</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">mounted() &#123;</span><br><span class="line">    <span class="keyword">const</span> timer = setInterval(<span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">        <span class="built_in">console</span>.log(<span class="number">1</span>)</span><br><span class="line">    &#125;, <span class="number">1000</span>)</span><br><span class="line">    <span class="comment">// 注册一次性钩子事件</span></span><br><span class="line">    <span class="keyword">this</span>.$once(<span class="string">'hook:beforeDestroy'</span>, () =&gt; &#123;</span><br><span class="line">        clearInterval(timer)</span><br><span class="line">    &#125;)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h4 id="2-vue-组件间通信"><a href="#2-vue-组件间通信" class="headerlink" title="2. vue 组件间通信"></a>2. vue 组件间通信</h4><ul>
<li><code>props / $emit</code> 父子组件间通信</li>
<li><code>EventBus：$emit / $on</code> 兄弟通信</li>
<li><code>vuex</code> 兄弟通信、父子通信、跨组件通信等</li>
<li><code>$attr / $listener</code> 父子通信</li>
<li><code>provide / inject</code> 父子跨级组件间的依赖注入（非响应式）</li>
<li><code>$parent / $children 与 ref</code> 父子通信</li>
<li><code>element-ui</code> 中自己实现的 <code>dispatch / broadcast</code> 跨父子间通信</li>
</ul>
<h4 id="3-自定义指令如何定义，他的生命周期"><a href="#3-自定义指令如何定义，他的生命周期" class="headerlink" title="3. 自定义指令如何定义，他的生命周期"></a>3. 自定义指令如何定义，他的生命周期</h4><p><code>Vue.directive()</code> 来定义全局指令</p>
<p>生命周期：</p>
<ul>
<li><strong>bind</strong> 一旦指令附加到元素时触发</li>
<li>inserted 一旦元素被添加带父元素时触发</li>
<li><strong>update</strong> 每当元素本身更新（但是子元素还未更新）时触发</li>
<li>componentUpdate 每当组件和子组件被更新时触发</li>
<li>unbind 一旦指令被移除时触发</li>
</ul>
<p>每个钩子都有 el、binding 和 vnode 参数可用</p>
<h4 id="4-vue-生命周期"><a href="#4-vue-生命周期" class="headerlink" title="4. vue 生命周期"></a>4. vue 生命周期</h4><ul>
<li><code>beforeCreate</code>： 暂时读不到实例的 <code>data</code> 和 <code>methods</code></li>
<li><code>created</code>： 已完成数据侦测、属性、方法的运算、<code>watch/event</code> 事件回调，此时 <code>$el</code> 属性目前不可见，暂无 <code>DOM</code> 渲染</li>
<li><code>beforeMounted</code>： 挂载之前被调用，相关的 <code>render</code> 函数首次被调用</li>
<li><code>mounted</code>： 挂载之后被调用</li>
<li><code>beforeUpdate/updated</code></li>
<li><code>beforeDestroy/destroyed</code></li>
</ul>
<h4 id="5-watch-和-computed-的区别"><a href="#5-watch-和-computed-的区别" class="headerlink" title="5. watch 和 computed 的区别"></a>5. watch 和 computed 的区别</h4><p><strong>computed</strong></p>
<ul>
<li>有缓存机制</li>
<li>可以依赖其他 <code>computed</code></li>
<li>不能与 <code>data</code> 中数据重复</li>
<li>不能接受参数</li>
</ul>
<p><strong>watch</strong></p>
<ul>
<li>可接受两个参数</li>
<li>监听时触发传入的回调</li>
<li>回调中允许异步操作</li>
<li>监听的属性必须存在</li>
</ul>
<h4 id="6-导航钩子有哪几种？"><a href="#6-导航钩子有哪几种？" class="headerlink" title="6. 导航钩子有哪几种？"></a>6. 导航钩子有哪几种？</h4><ol>
<li>全局导航守卫</li>
</ol>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 前置守卫</span></span><br><span class="line">router.beforeEach(<span class="function">(<span class="params">to, <span class="keyword">from</span>, next</span>) =&gt;</span> &#123;</span><br><span class="line">    <span class="comment">// （注意需释放 next() 钩子）</span></span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line"><span class="comment">// 后置钩子（没有 next）</span></span><br><span class="line">router.afterEach(<span class="function">(<span class="params">to, <span class="keyword">from</span></span>) =&gt;</span> &#123;</span><br><span class="line">    </span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>
<ol start="2">
<li>路由独享守卫</li>
</ol>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> router = <span class="keyword">new</span> Router(&#123;</span><br><span class="line">    routes: [&#123;</span><br><span class="line">        path: <span class="string">'index'</span>,</span><br><span class="line">        component: Index,</span><br><span class="line">        beforeEnter: <span class="function">(<span class="params">to, <span class="keyword">from</span>, next</span>) =&gt;</span> &#123; <span class="comment">/*code*/</span> &#125;</span><br><span class="line">    &#125;]</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>
<ol start="3">
<li>组件内导航钩子</li>
</ol>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">data() &#123;</span><br><span class="line">    <span class="keyword">return</span> &#123;</span><br><span class="line">        pro: <span class="string">'next'</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line">beforeRouteEnter: <span class="function">(<span class="params">to, <span class="keyword">from</span>, next</span>) =&gt;</span> &#123;&#125;</span><br><span class="line">beforeRouteUpdate: <span class="function">(<span class="params">to, <span class="keyword">from</span></span>) =&gt;</span> &#123;&#125;</span><br><span class="line">beforeRouteLeave: <span class="function">(<span class="params">to, <span class="keyword">from</span></span>) =&gt;</span> &#123;&#125;</span><br></pre></td></tr></table></figure>
<ul>
<li>可直接在组件内部直接定义</li>
<li><code>beforeRouteEnter</code> 还不能获取组件实例，因为此时组件还未实例化，可在 <code>next</code> 回调中访问组件实例</li>
</ul>
<h4 id="7-vue-中如何通过路由传递数据？区别在哪？"><a href="#7-vue-中如何通过路由传递数据？区别在哪？" class="headerlink" title="7. vue 中如何通过路由传递数据？区别在哪？"></a>7. vue 中如何通过路由传递数据？区别在哪？</h4><p><code>params</code> 和 <code>query</code></p>
<ul>
<li><code>params</code> 只能用 <code>name</code> 来引入路由，<code>query</code> 既可以用 <code>name</code>，又可以用 <code>path</code> （通常用 <code>path</code>）</li>
<li><code>params</code> 类似于 <code>post</code> 方法，参数不会在地址栏显示，而 <code>query</code> 则类似于 <code>get</code> 请求，显示在地址栏上</li>
</ul>
<h4 id="8-vue-router-的实现原理，history-和-hash-模式有什么区别"><a href="#8-vue-router-的实现原理，history-和-hash-模式有什么区别" class="headerlink" title="8. vue-router 的实现原理，history 和 hash 模式有什么区别"></a>8. vue-router 的实现原理，history 和 hash 模式有什么区别</h4><p><strong>hash 模式 和 history 模式</strong></p>
<ul>
<li><code>hash</code> 模式<ul>
<li><code>url</code> 中带有 <code>#</code> ，<code>#</code> 后面是 <code>hash</code> 值，<code>hash</code> 值的变化会触发 <code>hashchange</code> 这个事件，而且并不会发起请求重新刷新页面，通过监听这个事件能够实现更新页面内容的操作</li>
</ul>
</li>
<li><code>history</code> 模式<ul>
<li>切换历史状态： <code>forward</code>、<code>back</code>、<code>go</code>，这三个方法分别对应浏览器的前进、后退、跳转操作</li>
<li>修改历史状态： <code>pushState</code>、<code>replaceState</code>，这两个方法接收三个参数（stateObj, title, url）</li>
</ul>
</li>
</ul>
<p><strong>history 缺点：</strong></p>
<ul>
<li><code>hash</code> 模式下，仅 <code>#</code> 前面的内容会被包含在请求中，对于后端来说，即使没有做到对路由的全覆盖，也不会返回 <code>404</code> 错误</li>
<li><code>history</code> 模式下，前端 <code>url</code> 必须和实际向后端发起请求的 <code>url</code> 一致，如 <code>http://www.xxx.com/book/a</code>，如果后端缺少对 <code>/book/a</code> 的路由处理，则 返回 <code>404</code> 错误</li>
</ul>
<h4 id="9-vue-中设置-key-的作用"><a href="#9-vue-中设置-key-的作用" class="headerlink" title="9.  vue 中设置 key 的作用"></a>9.  vue 中设置 key 的作用</h4><p><code>key</code> 的作用主要是为了高效的更新虚拟 <code>DOM</code>，<code>diff</code> 算法在没有 <code>key</code> 标志下会逐一对 虚拟 <code>DOM</code> 进行操作更新，如果设置了 <code>key</code> 作为唯一标识， <code>diff</code> 算法就可以正确识别出此节点，快速找出需要更新的节点</p>
<h4 id="10-vue-中的-diff-算法"><a href="#10-vue-中的-diff-算法" class="headerlink" title="10. vue 中的 diff 算法"></a>10. vue 中的 diff 算法</h4><h4 id="11-vue-中对数据的变化侦测"><a href="#11-vue-中对数据的变化侦测" class="headerlink" title="11. vue 中对数据的变化侦测"></a>11. vue 中对数据的变化侦测</h4><p><code>vue</code> 的核心原理是通过 <code>ES5</code> 的 <code>Object.definedProperty</code> 来对数据进行监听，结合<strong>发布者订阅者模式</strong>进行数据侦测。</p>
<p><code>Observer</code> 类用于将数据转换为响应式，递归对每一个数据的 <code>getter</code> 和 <code>setter</code> 属性进行劫持，即在 <code>getter</code> 中进行依赖收集，在 <code>setter</code> 中触发更新依赖，依赖集中收集到 <code>Dep</code> 管理器中进行管理。而通过 <code>Watcher</code> 类进行依赖收集</p>
<h4 id="vue-中对普通对象和-数组-的监听有何不同？"><a href="#vue-中对普通对象和-数组-的监听有何不同？" class="headerlink" title="vue 中对普通对象和 数组 的监听有何不同？"></a>vue 中对普通对象和 数组 的监听有何不同？</h4><p><code>vue</code> 中对普通对象的侦测是通过 <code>Object.definedProperty</code> 来进行数据侦测，在修改对象的时候能够被侦测到数据的改变。</p>
<p>但是 <code>Object.definedProperty</code> 无法对数组元素进行侦测，<code>vue</code> 中的做法是通过<strong>装饰者模式</strong>，对数组原型方法进行一层包装，在原型方法包装的基础上进行触发更新的操作，对于不支持 <code>__proto__</code> 方法的环境下，<code>vue</code> 中直接将数组方法挂载到<strong>数组本身</strong>。</p>
<h4 id="vue2-数据侦测的缺陷"><a href="#vue2-数据侦测的缺陷" class="headerlink" title="vue2 数据侦测的缺陷"></a>vue2 数据侦测的缺陷</h4><p><code>Object.definedProperty</code> 无法对对象的<strong>删除</strong>和<strong>添加</strong>进行侦测，故提供了两个 <code>api</code> 使用，<code>$set</code> 和 <code>$delete</code>。</p>
<h4 id="vue-中的设计模式"><a href="#vue-中的设计模式" class="headerlink" title="vue 中的设计模式"></a>vue 中的设计模式</h4><ul>
<li>发布订阅模式</li>
</ul>
<p>数据侦测方法、<code>$on/$emit</code> 自定义事件</p>
<ul>
<li>装饰器模式</li>
</ul>
<p>对数组方法的侦测，扩展数组方法功能</p>
<ul>
<li>策略模式</li>
</ul>
<p>合并参数时对于 <code>data</code> 和 <code>props</code> 等使用不同策略</p>
<ul>
<li>代理模式</li>
</ul>
<p><code>vue</code> 中对于 <code>data</code> 中数据实际上储存在 <code>vm._data</code> 中，代理模式实际上对 <code>this.xx</code> 进行了一下代理，实际上访问的是 <code>vm._data.xx</code> 的值</p>
<h4 id="12-vue-如何优化首屏加载速度"><a href="#12-vue-如何优化首屏加载速度" class="headerlink" title="12. vue 如何优化首屏加载速度"></a>12. vue 如何优化首屏加载速度</h4><ul>
<li>第三方库按 <code>CDN</code> 引入</li>
<li><code>vue-router</code> 路由懒加载</li>
<li>压缩图片资源</li>
<li>静态文件本地缓存</li>
</ul>
<h4 id="13-切换到新路由时，页面要滚动到顶部或保持原先滚动位置怎么做？"><a href="#13-切换到新路由时，页面要滚动到顶部或保持原先滚动位置怎么做？" class="headerlink" title="13. 切换到新路由时，页面要滚动到顶部或保持原先滚动位置怎么做？"></a>13. 切换到新路由时，页面要滚动到顶部或保持原先滚动位置怎么做？</h4><p>当创建 Router 实例的时候，可以提供一个 <code>scrollBehavior</code> 方法实现：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> router = <span class="keyword">new</span> Router(&#123;</span><br><span class="line">    routes: [...],</span><br><span class="line">    scrollBehavior(to, <span class="keyword">from</span>, savedPosition) &#123;</span><br><span class="line">        <span class="comment">// return 期望滚动到的位置</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>
<h4 id="14-nextTick-使用场景"><a href="#14-nextTick-使用场景" class="headerlink" title="14. $nextTick() 使用场景"></a>14. $nextTick() 使用场景</h4><p>在下次 <code>DOM</code> 更新循环结束之后执行延迟回调，可在回调中获取更新后的 <code>DOM</code>，内部优先使用 <strong>微任务</strong> 来执行回调，不支持则降级为 <strong>宏任务</strong></p>
<p><strong>解决的问题</strong>：有些时候改变了数据之后需要立即对 <code>DOM</code> 进行操作，此时获取的 <code>DOM</code> 仍是未更新前的 <code>DOM</code>，此时即需要使用 <code>$nextTick</code></p>
<h4 id="15-vue-和-react-的区别"><a href="#15-vue-和-react-的区别" class="headerlink" title="15. vue 和 react 的区别"></a>15. vue 和 react 的区别</h4><ol>
<li>React 严格上只针对 MVC 的 view 层，Vue 则是 MVVM 模式</li>
<li>virtual DOM 不一样，vue 会跟踪 每一个组件的依赖关系，不需要重新渲染整个组件树。而对于 React 而言，每当应用的状态被改变时，全部组件都会重新渲染，所以 React 中会需要 shouldComponentUpdate 这个生命周期方法来控制</li>
<li>组件写法不一样，React 推荐做法是 JSX + inline style，即将 HTML、css 全写进 JavaScript 中，即 ‘all in js’。vue 推荐 webpack + vue-loader 的单文件组件格式，即 html、css、js 写在同一个文件中</li>
<li>vue 实现双向数据绑定，react 数据流动是单向的</li>
<li>state 对象在 react 中不可变，需要使用 setState 方法更新。在 Vue 则不需要，只需在 data 中声明</li>
</ol>
<h4 id="vuex-简述"><a href="#vuex-简述" class="headerlink" title="vuex 简述"></a>vuex 简述</h4><p><strong>vuex 核心是 store</strong> ，可以理解为一个数据或状态容器，与全局对象有些不同：</p>
<ul>
<li><code>vuex</code> 状态储存是响应式的</li>
<li>不可直接更改 <code>store</code> 中的状态，需要通过显式的提交（<code>commit</code>） <code>mutation</code> ，<code>action</code> 中可进行异步操作</li>
</ul>
<p><strong>五个基本对象</strong>：</p>
<ul>
<li><code>State</code>：单一状态树</li>
<li><code>Getter</code>：获取状态树中的数据</li>
<li><code>Mutation</code>：更改 <code>store</code> 中数据的唯一方法</li>
<li><code>Action</code>：用于提交 <code>mutation</code>，可以包含异步操作</li>
<li><code>Module</code>：将 <code>state</code> 进行拆分</li>
</ul>
<h3 id="Axios-相关"><a href="#Axios-相关" class="headerlink" title="Axios 相关"></a><a href="https://zhuanlan.zhihu.com/p/97813399" target="_blank" rel="noopener">Axios 相关</a></h3><ol>
<li>为什么 <code>axios</code> 既可以当函数调用，也可以当对象使用，比如 a<code>xios({})</code>、 <code>axios.get</code></li>
</ol>
<blockquote>
<p>axios 本质是一个函数，并在函数上赋值了一些别名方法，比如 get、post 方法，实际上最终调用的还是 Axios.prototype.request 函数</p>
</blockquote>
<ol start="2">
<li><code>axios</code> 调用流程</li>
</ol>
<blockquote>
<p>实际调用的是 Axios.prototype.request 方法，最终返回的是 promise 链式调用，实际请求是在 dispatchRequest 中派发的</p>
</blockquote>
<ol start="3">
<li>拦截器原理</li>
</ol>
<blockquote>
<p>使用 axios.interceptors.request.use 添加请求成功和失败的拦截器函数，使用 axios.interceptors.response.use 添加响应成功和失败的拦截器函数。在 Axios.prototype.request 函数组成 promise 链式调用时，Interceptors.prototype.forEach 遍历请求和响应拦截器添加到真正发送请求 dispatchRequest 的两端，从而做到请求前拦截和响应后拦截。拦截器也支持用 Interceptors.prototype.eject 方法移除</p>
</blockquote>
<ol start="4">
<li><code>axios</code> 取消功能实现</li>
</ol>
<blockquote>
<p>通过传递 config 配置 cancelToken 的形式来取消的，判断有传 cancelToken，在 promise 链式调用的 dispatchRequest 抛出错误，在 adapter 中 request.abort() 取消请求，使 promise 走向 reject，被用户捕获取消信息</p>
</blockquote>
<ol start="5">
<li>如何支持浏览器和 <code>node</code> 中发送请求</li>
</ol>
<blockquote>
<p>axios.defaults.adapter 默认配置中根据环境判断是浏览器还是 node 环境，使用对应的适配器，适配器支持自定义</p>
</blockquote>
<h3 id="性能优化"><a href="#性能优化" class="headerlink" title="性能优化"></a>性能优化</h3><h4 id="1-预加载和懒加载"><a href="#1-预加载和懒加载" class="headerlink" title="1. 预加载和懒加载"></a>1. <a href="https://juejin.im/post/5b0c3b53f265da09253cbed0" target="_blank" rel="noopener">预加载和懒加载</a></h4><p><strong>懒加载</strong></p>
<p><strong>概念：</strong></p>
<ul>
<li><p>懒加载也称延迟加载，是指在长网页中延迟加载图像，一种<strong>优化网页性能</strong>的方式。</p>
</li>
<li><p>优先加载<strong>可视区域</strong>的图像，可视区域外的图像不会加载，适用于图片很多，页面很长的电商网站场景中</p>
</li>
</ul>
<p><strong>好处：</strong></p>
<ul>
<li>提升用户体验，减少等待时间</li>
<li>减少无用资源的加载，降低服务器压力</li>
</ul>
<p><strong>原理：</strong></p>
<ul>
<li>首先将页面上图片 <code>src</code> 设置为空或默认图片，将真实路径设置在其他属性中，如 data-original 属性中</li>
<li>当页面滚动时候监听 <code>scroll</code> 事件，判断图片是否进入可是区域，是则设置 <code>src</code> 属性值为 <code>data-original</code> 的值</li>
</ul>
<p><strong>预加载</strong></p>
<p><strong>概念：</strong></p>
<p>性能优化技术，预先告知浏览器某些资源可能在将来会被使用到。预加载简单来说就是将所有所需资源提前加载到本地，这样后面在需要使用到时就直接从<strong>本地缓存中</strong>取资源</p>
<p><strong>好处：</strong></p>
<p>对主要内容进行加载，以提供良好的用户体验，减少用户等待时间</p>
<p><strong>实现预加载方法：</strong></p>
<ul>
<li><code>CSS（background）</code>：通过屏幕外的背景图，先加载需要的这几张图</li>
<li><strong>JS（Image）</strong></li>
<li><code>Ajax</code>（可预加载 <code>css</code>、<code>js</code>、图片等）</li>
</ul>
<p>最常用的是 <strong>new Image()</strong> ，设置其 <code>src</code> 属性实现图片的预加载。只要浏览器把图片下载到本地，<strong>同样的 src 就会缓存</strong>，这是最基本最实用的预加载方法。</p>
<h4 id="2-spa-单页应用和多页应用的选型场景"><a href="#2-spa-单页应用和多页应用的选型场景" class="headerlink" title="2. spa 单页应用和多页应用的选型场景"></a>2. spa 单页应用和多页应用的选型场景</h4><h4 id="3-js-实现重定向的几种方式"><a href="#3-js-实现重定向的几种方式" class="headerlink" title="3. js 实现重定向的几种方式"></a>3. js 实现重定向的几种方式</h4><ul>
<li>window.location.href</li>
<li>window.navigate</li>
<li>self.location</li>
</ul>
<h4 id="css-兼容的-4-种方案-1"><a href="#css-兼容的-4-种方案-1" class="headerlink" title="css 兼容的 4 种方案"></a>css 兼容的 4 种方案</h4><ul>
<li>浏览器 <code>css</code> 样式初始化 （<code>normalize.css</code>）</li>
<li>浏览器私有属性（<code>css</code> 属性前缀，如 <code>-webkit-</code>、<code>-moz-</code>、<code>-ms-</code>）</li>
<li><code>css hack</code> 写法</li>
<li><strong>自动化插件（Autoprefixer 插件）</strong></li>
</ul>
<h4 id="margin-越界问题"><a href="#margin-越界问题" class="headerlink" title="margin 越界问题"></a>margin 越界问题</h4><ul>
<li><p>概念：即<strong>外边距合并</strong>，当普通文档流中两个<strong>垂直外边距</strong>相遇时，将发生合并为外边距较大者（发生在上下兄弟元素之前，或父子元素之间），但左右外边距不会合并</p>
</li>
<li><p>合并规则：</p>
<ul>
<li>两外边距都为正数，合并结果为两者中较大的值</li>
<li>两外边距都为负数，合并结果为两者绝对值中较大的值</li>
<li>两外边距一正一负，合并结果为两者相加的和</li>
</ul>
</li>
</ul>
<h4 id="js-深拷贝"><a href="#js-深拷贝" class="headerlink" title="js 深拷贝"></a>js 深拷贝</h4><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// js 简易深拷贝，使用递归方式实现数组、对象的深拷贝</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">deepClone</span>(<span class="params">obj</span>) </span>&#123;</span><br><span class="line">    <span class="comment">// 区分数组还是对象</span></span><br><span class="line">    <span class="keyword">var</span> objClone = <span class="built_in">Array</span>.isArray(obj) ? [] : &#123;&#125;</span><br><span class="line">    <span class="comment">// 引用数据类型判断</span></span><br><span class="line">    <span class="keyword">if</span>(obj &amp;&amp; <span class="keyword">typeof</span> obj === <span class="string">'object'</span>) &#123;</span><br><span class="line">        <span class="comment">// 遍历</span></span><br><span class="line">        <span class="keyword">for</span>(<span class="keyword">var</span> key <span class="keyword">in</span> obj) &#123;</span><br><span class="line">            <span class="keyword">if</span>(obj.hasOwnProperty(key)) &#123;</span><br><span class="line">                <span class="comment">// 如果子属性为引用数据类型，递归拷贝，简单数据类型直接拷贝</span></span><br><span class="line">                <span class="keyword">if</span>(obj[key] &amp;&amp; <span class="keyword">typeof</span> obj[key] === <span class="string">'object'</span>) &#123;</span><br><span class="line">                    objClone[key] = deepClone(obj[key])</span><br><span class="line">                &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                    objClone[key] = obj[key]</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> objClone</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h4 id="如何性能优化？从几个点进行？"><a href="#如何性能优化？从几个点进行？" class="headerlink" title="如何性能优化？从几个点进行？"></a>如何性能优化？从几个点进行？</h4><ul>
<li>开启 <code>gzip</code> 压缩功能</li>
<li>引入 <code>cdn</code></li>
<li>路由懒加载</li>
<li>第三方组件按需加载而不是全部加载</li>
<li>较小的图片资源用 <code>base64</code> 嵌入 <code>src</code> 中，减少 <code>http</code> 请求</li>
</ul>
<h4 id="缓存有哪些？"><a href="#缓存有哪些？" class="headerlink" title="缓存有哪些？"></a>缓存有哪些？</h4><ul>
<li>本地缓存： <code>cookie</code>、<code>sessionStorage</code>、<code>localStorage</code></li>
<li><code>http</code> 缓存：强缓存、协商缓存</li>
</ul>
<h4 id="SPA-项目优化"><a href="#SPA-项目优化" class="headerlink" title="SPA 项目优化"></a>SPA 项目优化</h4><ul>
<li>开启 <code>gzip</code> 压缩功能，压缩率大约能 <code>70%</code></li>
<li>引入 <code>CDN</code>，比如 <code>vue</code>、<code>vuex</code>、<code>vue-router</code>、<code>echarts</code> 等</li>
<li>路由懒加载</li>
<li>某些第三方组件按需加载而不是全部加载，比如 <code>echarts</code> 单独引入柱状图等</li>
<li>较小的图片资源用 <code>base64</code> 嵌入 <code>src</code> 中，减少 <code>http</code> 请求</li>
</ul>
<h3 id="webpack"><a href="#webpack" class="headerlink" title="webpack"></a>webpack</h3><h4 id="webpack-是怎么进行打包的？"><a href="#webpack-是怎么进行打包的？" class="headerlink" title="webpack 是怎么进行打包的？"></a>webpack 是怎么进行打包的？</h4><ul>
<li><code>webpack</code> 就行一条生产线，输入经过一系列流程之后转换成输出结果</li>
<li>生产线上的每一个处理流程的职责都是单一的，多个处理流程之间存在依赖关系，处理完当前的才能交给下一个流程处理</li>
<li><strong>插件</strong>就像是一个插入到生产线上的一个功能，在特定的时机对生产线上的资源做处理</li>
<li><code>webpack</code> 通过 <code>Tapable</code> 来组织这条复杂的生产线</li>
<li><code>webpack</code> 在运行过程中会广播事件，<strong>插件</strong>只需要监听它所关心的事件，就能加入到这条生产线中，改变生产线的运作</li>
</ul>
<h4 id="webpack-构建流程？"><a href="#webpack-构建流程？" class="headerlink" title="webpack 构建流程？"></a>webpack 构建流程？</h4><ol>
<li><p><strong>初始化参数</strong>：从配置文件和 shell 语句中读取与合并参数，得到最终参数</p>
</li>
<li><p><strong>开始编译</strong>：用上一步得到的参数初始化 Compiler 对象，加载所有配置的插件，执行对象的 run 方法开始执行编译</p>
</li>
<li><p><strong>确定入口</strong>：根据配置中的 entry 找出所有入口</p>
</li>
<li><p><strong>编译模块</strong>：从入口文件出发，调用所有配置的 Loader 对模块进行翻译，再找出该模块依赖的模块，再递归本步骤直到所有入口依赖的文件都经过了本步骤的处理</p>
</li>
<li><p><strong>完成模块编译</strong>：在经过第 4 步使用 Loader 翻译完所有模块后，得到了每个模块被翻译后的最终内容以及他们之间的依赖关系</p>
</li>
<li><p><strong>输出资源</strong>：根据模块入口和模块之间的依赖关系，组装成一个个包含多个模块的 Chunk ，再把每个 Chunk 转换成一个单独的文件加入到输出列表，这步是可以修改输出内容的最后机会</p>
</li>
<li><p><strong>输出完成</strong>：在确定好输出内容后，根据配置确定输出的路径和文件名，把文件内容写入到文件系统</p>
</li>
</ol>
<p>在以上过程中， webpack 会在特定的时间点广播出特定的事件，插件在监听到感兴趣的事件后会执行特定的逻辑，并且插件可以调用 webpack 提供的 api 改变 webpack 的运行结果</p>
<p>项目中是怎么进行优化的</p>
<p>loader 和 plugin 是什么？</p>
<p>插件原理？</p>
<p>xss 、csrf 怎么处理？</p>
<p>组件化设计？</p>
<p>响应式与自适应方案？</p>
<p>主题切换方案？</p>
<p>可视化方案？</p>
<h3 id="参考："><a href="#参考：" class="headerlink" title="参考："></a>参考：</h3><p><a href="[https://github.com/luoxue-victor/jijiang-blog/blob/master/src/views/javascript/JS%E5%8E%9F%E7%94%9F%E9%9D%A2%E7%BB%8F%E4%BB%8E%E5%88%9D%E7%BA%A7%E5%88%B0%E9%AB%98%E7%BA%A7.md](https://github.com/luoxue-victor/jijiang-blog/blob/master/src/views/javascript/JS原生面经从初级到高级.md">JS 原生面经从初级到高级【近1.5W字】</a>)</p>
<p><a href="https://sanyuan0704.github.io/frontend_daily_question/nav/" target="_blank" rel="noopener">前端每日一问</a></p>
<p><a href="https://yuchengkai.cn/docs/frontend" target="_blank" rel="noopener">前端进阶之道</a></p>
<p><a href="https://mp.weixin.qq.com/s/op3EaSXKTCXwYt_uRvhePg" target="_blank" rel="noopener">高级进阶：深度揭秘 Promise 注册微任务和执行过程</a></p>
<p><a href="https://zhuanlan.zhihu.com/p/97813399" target="_blank" rel="noopener">学习 axios 源码整体架构，打造属于自己的请求库</a></p>

        </div>

        <blockquote class="post-copyright">
    
    <div class="content">
        
<span class="post-time">
    最后更新时间：<time datetime="2020-08-10T08:11:06.636Z" itemprop="dateUpdated">2020-08-10 16:11:06</time>
</span><br>


        
        关于学习类文章网上已经有非常多，而此处文章都是我在学习过程中整理摘录的笔记，参考文章可以点击文末的参考链接进行查阅
        
    </div>
    
    <footer>
        <a href="https://lafen.gitee.io">
            <img src="/img/avatar.jpg" alt="lafen">
            lafen
        </a>
    </footer>
</blockquote>

        
<div class="page-reward">
    <a id="rewardBtn" href="javascript:;" class="page-reward-btn waves-effect waves-circle waves-light">赏</a>
</div>



        <div class="post-footer">
            
	<ul class="article-tag-list"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/前端/">前端</a></li></ul>


            
<div class="page-share-wrap">
    

<div class="page-share" id="pageShare">
    <ul class="reset share-icons">
      <li>
        <a class="weibo share-sns" target="_blank" href="http://service.weibo.com/share/share.php?url=https://lafen.gitee.io/2020/03/30/前端总结知识点/前端总结知识点/&title=《前端总结知识点》 — lafen&pic=https://lafen.gitee.io/img/avatar.jpg" data-title="微博">
          <i class="icon icon-weibo"></i>
        </a>
      </li>
      <li>
        <a class="weixin share-sns wxFab" href="javascript:;" data-title="微信">
          <i class="icon icon-weixin"></i>
        </a>
      </li>
      <li>
        <a class="qq share-sns" target="_blank" href="http://connect.qq.com/widget/shareqq/index.html?url=https://lafen.gitee.io/2020/03/30/前端总结知识点/前端总结知识点/&title=《前端总结知识点》 — lafen&source=lafen's personal blog" data-title=" QQ">
          <i class="icon icon-qq"></i>
        </a>
      </li>
      <li>
        <a class="facebook share-sns" target="_blank" href="https://www.facebook.com/sharer/sharer.php?u=https://lafen.gitee.io/2020/03/30/前端总结知识点/前端总结知识点/" data-title=" Facebook">
          <i class="icon icon-facebook"></i>
        </a>
      </li>
      <li>
        <a class="twitter share-sns" target="_blank" href="https://twitter.com/intent/tweet?text=《前端总结知识点》 — lafen&url=https://lafen.gitee.io/2020/03/30/前端总结知识点/前端总结知识点/&via=https://lafen.gitee.io" data-title=" Twitter">
          <i class="icon icon-twitter"></i>
        </a>
      </li>
      <li>
        <a class="google share-sns" target="_blank" href="https://plus.google.com/share?url=https://lafen.gitee.io/2020/03/30/前端总结知识点/前端总结知识点/" data-title=" Google+">
          <i class="icon icon-google-plus"></i>
        </a>
      </li>
    </ul>
 </div>



    <a href="javascript:;" id="shareFab" class="page-share-fab waves-effect waves-circle">
        <i class="icon icon-share-alt icon-lg"></i>
    </a>
</div>



        </div>
    </div>

    
<nav class="post-nav flex-row flex-justify-between">
  
    <div class="waves-block waves-effect prev">
      <a href="/2020/07/12/hello-world/" id="post-prev" class="post-nav-link">
        <div class="tips"><i class="icon icon-angle-left icon-lg icon-pr"></i> Prev</div>
        <h4 class="title">Hello World</h4>
      </a>
    </div>
  

  
    <div class="waves-block waves-effect next">
      <a href="/2020/01/10/2020慢一点/2020慢一点/" id="post-next" class="post-nav-link">
        <div class="tips">Next <i class="icon icon-angle-right icon-lg icon-pl"></i></div>
        <h4 class="title">2020慢一点</h4>
      </a>
    </div>
  
</nav>



    




















</article>

<div id="reward" class="page-modal reward-lay">
    <a class="close" href="javascript:;"><i class="icon icon-close"></i></a>
    <h3 class="reward-title">
        <i class="icon icon-quote-left"></i>
        打笔巨款？~
        <i class="icon icon-quote-right"></i>
    </h3>
    <div class="reward-content">
        
        <div class="reward-code">
            <img id="rewardCode" src="/img/wechat.jpg" alt="打赏二维码">
        </div>
        
        <label class="reward-toggle">
            <input id="rewardToggle" type="checkbox" class="reward-toggle-check" data-wechat="/img/wechat.jpg" data-alipay="/img/alipay.jpg">
            <div class="reward-toggle-ctrol">
                <span class="reward-toggle-item wechat">微信</span>
                <span class="reward-toggle-label"></span>
                <span class="reward-toggle-item alipay">支付宝</span>
            </div>
        </label>
        
    </div>
</div>



</div>

        <footer class="footer">
    <div class="top">
        
<p>
    <span id="busuanzi_container_site_uv" style="display:none">
        站点总访客数：<span id="busuanzi_value_site_uv"></span>
    </span>
    <span id="busuanzi_container_site_pv" style="display:none">
        站点总访问量：<span id="busuanzi_value_site_pv"></span>
    </span>
</p>


        <p>
            
                <span><a href="/atom.xml" target="_blank" class="rss" title="rss"><i class="icon icon-lg icon-rss"></i></a></span>
            
            <span>博客内容遵循 <a rel="license" href="https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh">知识共享 署名 - 非商业性 - 相同方式共享 4.0 国际协议</a></span>
        </p>
    </div>
    <div class="bottom">
        <p><span>lafen &copy; 2019 - 2020</span>
            <span>
                
                Power by <a href="http://hexo.io/" target="_blank">Hexo</a> Theme <a href="https://github.com/yscoder/hexo-theme-indigo" target="_blank">indigo</a>
            </span>
        </p>
    </div>
</footer>

    </main>
    <div class="mask" id="mask"></div>
<a href="javascript:;" id="gotop" class="waves-effect waves-circle waves-light"><span class="icon icon-lg icon-chevron-up"></span></a>



<div class="global-share" id="globalShare">
    <ul class="reset share-icons">
      <li>
        <a class="weibo share-sns" target="_blank" href="http://service.weibo.com/share/share.php?url=https://lafen.gitee.io/2020/03/30/前端总结知识点/前端总结知识点/&title=《前端总结知识点》 — lafen&pic=https://lafen.gitee.io/img/avatar.jpg" data-title="微博">
          <i class="icon icon-weibo"></i>
        </a>
      </li>
      <li>
        <a class="weixin share-sns wxFab" href="javascript:;" data-title="微信">
          <i class="icon icon-weixin"></i>
        </a>
      </li>
      <li>
        <a class="qq share-sns" target="_blank" href="http://connect.qq.com/widget/shareqq/index.html?url=https://lafen.gitee.io/2020/03/30/前端总结知识点/前端总结知识点/&title=《前端总结知识点》 — lafen&source=lafen's personal blog" data-title=" QQ">
          <i class="icon icon-qq"></i>
        </a>
      </li>
      <li>
        <a class="facebook share-sns" target="_blank" href="https://www.facebook.com/sharer/sharer.php?u=https://lafen.gitee.io/2020/03/30/前端总结知识点/前端总结知识点/" data-title=" Facebook">
          <i class="icon icon-facebook"></i>
        </a>
      </li>
      <li>
        <a class="twitter share-sns" target="_blank" href="https://twitter.com/intent/tweet?text=《前端总结知识点》 — lafen&url=https://lafen.gitee.io/2020/03/30/前端总结知识点/前端总结知识点/&via=https://lafen.gitee.io" data-title=" Twitter">
          <i class="icon icon-twitter"></i>
        </a>
      </li>
      <li>
        <a class="google share-sns" target="_blank" href="https://plus.google.com/share?url=https://lafen.gitee.io/2020/03/30/前端总结知识点/前端总结知识点/" data-title=" Google+">
          <i class="icon icon-google-plus"></i>
        </a>
      </li>
    </ul>
 </div>


<div class="page-modal wx-share" id="wxShare">
    <a class="close" href="javascript:;"><i class="icon icon-close"></i></a>
    <p>扫一扫，分享到微信</p>
    <img src="" alt="微信分享二维码">
</div>




    <script src="//cdn.bootcss.com/node-waves/0.7.4/waves.min.js"></script>
<script>
var BLOG = { ROOT: '/', SHARE: true, REWARD: true };


</script>

<script src="//unpkg.com/hexo-theme-material-indigo@latest/js/main.min.js"></script>


<div class="search-panel" id="search-panel">
    <ul class="search-result" id="search-result"></ul>
</div>
<template id="search-tpl">
<li class="item">
    <a href="{path}" class="waves-block waves-effect">
        <div class="title ellipsis" title="{title}">{title}</div>
        <div class="flex-row flex-middle">
            <div class="tags ellipsis">
                {tags}
            </div>
            <time class="flex-col time">{date}</time>
        </div>
    </a>
</li>
</template>

<script src="//unpkg.com/hexo-theme-material-indigo@latest/js/search.min.js" async></script>






<script async src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>



<script>
(function() {
    var OriginTitile = document.title, titleTime;
    document.addEventListener('visibilitychange', function() {
        if (document.hidden) {
            document.title = '死鬼去哪里了！';
            clearTimeout(titleTime);
        } else {
            document.title = '(つェ⊂)咦!又好了!';
            titleTime = setTimeout(function() {
                document.title = OriginTitile;
            },2000);
        }
    });
})();
</script>



<script src="/live2dw/lib/L2Dwidget.min.js?094cbace49a39548bed64abff5988b05"></script><script>L2Dwidget.init({"pluginRootPath":"live2dw/","pluginJsPath":"lib/","pluginModelPath":"assets/","tagMode":false,"debug":false,"model":{"scale":1,"jsonPath":"/live2dw/assets/shizuku.model.json"},"display":{"positon":"right","width":150,"height":300},"mobile":{"show":true,"scale":0.8},"react":{"opacity":0.8,"opacityDefault":0.8,"opacityOnHover":0.6},"log":false});</script></body>
</html>
